diff --git a/README.md b/README.md
index f4c31eee557bb768d2dce36f04bc851edbbf6976..fde9882332da7a75014e90a1d60cab5d049f58a3 100644
--- a/README.md
+++ b/README.md
@@ -12,21 +12,29 @@ ch32v003fun contains:
 1. EVT Folder for running demos from the ch32v003 EVT.
 2. Barebones. A project that does not use the HAL or EVT.
 3. "minichlink" which uses the WCH CH-Link with libusb, for cross-platform use.
+4. An extra copy of libgcc so you can use unusual risc-v build chains, located in the `misc/libgcc.a`.
+
+IN PROGRESS:
+1. A folder named "ch32v003fun" containing a single self-contained source file and header file for compling apps for the ch32v003.
 
 ## System Prep
 
-On WSL or Debian based OSes `apt-get install build-essential libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev`
+On WSL or Debian based OSes `apt-get install build-essential libnewlib-dev gcc-riscv64-unknown-elf libusb-1.0-0-dev libudev-dev`
+
+On Windows, download and install (to system) this copy of GCC10. https://gnutoolchains.com/risc-v/
+
+You can use the pre-compiled minichlink or 
 
 ## Running
 
 ```
-cd barebones
+cd examples/blink
 make
 ```
 
-In Linux this will "just work" using the `miniwchlink`. In Windows, you can use this or you can use the WCH-LinkUtility to flash the built hex file.
+In Linux this will "just work" using the `minichlink`.   In Windows if you want to use minichlink, you will need to use Zadig to install WinUSB to the WCH-Link interface 0.
 
-If you are in Windows, you will need to use zadig to install the libusb driver to the WCH-Link interface 0.
+In Windows, you can use this or you can use the WCH-LinkUtility to flash the built hex file.
 
 ## For using EVT demos, check out the EVT folder.
 
@@ -38,7 +46,7 @@ It enumerates as 2 interfaces.
 
 If you want to mess with the programming code in Windows, you will have to install WinUSB to the interface 0.  Then you can uninstall it in Device Manager under USB Devices.
 
-## miniwchlink
+## minichlink
 
 I wrote some libusb copies of some of the basic functionality from WCH-Link, so you can use the little programmer dongle they give you to program the ch32v003. 
 
diff --git a/attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_pcb b/attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_pcb
similarity index 100%
rename from attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_pcb
rename to attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_pcb
diff --git a/attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_pro b/attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_pro
similarity index 100%
rename from attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_pro
rename to attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_pro
diff --git a/attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_sch b/attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_sch
similarity index 100%
rename from attic/hardware/ch32v003f4u6_with_wsled_nomic/ch32v003f4u6_with_wsled.kicad_sch
rename to attic/hardware/ch32v003f4u6_with_wsleds/ch32v003f4u6_with_wsled.kicad_sch
diff --git a/attic/on-wire-protocol-notes.txt b/attic/on-wire-protocol-notes.txt
index d3edeb87868247dae1e811de4cc72cc08d068b54..70580c59c14ade0947c77f3e1eb1a15366168ffe 100644
--- a/attic/on-wire-protocol-notes.txt
+++ b/attic/on-wire-protocol-notes.txt
@@ -120,10 +120,10 @@ Then the data starts.
 11 1111101 01011010 10100101 00000100 00000000
 11 1111011 01011010 10100101 00000100 00000000
 11 1111000/00000000 00000001 00000100 00000011 << I thought this was "turned around" but it seems the main uc controls the clocking and it's up to the uc to drive high.
-10 0100010/00000000 01001111 00000011 10000010
-10 0100001 10000000 00000000 00000000 00000001
-10 0100001 10000000 00000000 00000000 00000001
-10 0101100/00001000 00000000 00000000 00000010
+1 0010001 0/00000000 01001111 00000011 10000010
+1 0010000 1 10000000 00000000 00000000 00000001
+1 0010000 1 10000000 00000000 00000000 00000001
+1 0010110 0/00001000 00000000 00000000 00000010
 --
 10 0100010/00000000 01001111 00000011 10000010
 11 1111110/00000000 00110000 00000101 00000000
diff --git a/minichlink/wch_dump_flash.c b/attic/wch_dump_flash.c
similarity index 100%
rename from minichlink/wch_dump_flash.c
rename to attic/wch_dump_flash.c
diff --git a/ch32v003evt/embedlibc.c b/ch32v003evt/embedlibc.c
index d8c69ee72b063d08c19ec8c056738267c8d02319..e40632bf5985e02a28e69be7fb87438745b40e97 100644
--- a/ch32v003evt/embedlibc.c
+++ b/ch32v003evt/embedlibc.c
@@ -15,6 +15,7 @@ int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const cha
 static int __puts_uart(char *s, int len, void *buf)
 {
 	_write( 0, s, len );
+	return len;
 }
 
 int printf(const char* format, ...)
@@ -105,9 +106,9 @@ int wctomb(char *s, wchar_t wc)
 }
 size_t strlen(const char *s) { const char *a = s;for (; *s; s++);return s-a; }
 size_t strnlen(const char *s, size_t n) { const char *p = memchr(s, 0, n); return p ? p-s : n;}
-void *memset(void *dest, int c, size_t n) { unsigned char *s = dest; for (; n; n--, s++) *s = c; }
-char *strcpy(char *d, const char *s) { for (; (*d=*s); s++, d++); }
-char *strncpy(char *d, const char *s, size_t n) { for (; n && (*d=*s); n--, s++, d++); }
+void *memset(void *dest, int c, size_t n) { unsigned char *s = dest; for (; n; n--, s++) *s = c; return dest; }
+char *strcpy(char *d, const char *s) { for (; (*d=*s); s++, d++); return d; }
+char *strncpy(char *d, const char *s, size_t n) { for (; n && (*d=*s); n--, s++, d++); return d; }
 int strcmp(const char *l, const char *r)
 {
 	for (; *l==*r && *l; l++, r++);
diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
new file mode 100644
index 0000000000000000000000000000000000000000..18ce488f90546ec317a470f20032a03dd1b70ae2
--- /dev/null
+++ b/ch32v003fun/ch32v003fun.c
@@ -0,0 +1,855 @@
+// Mixture of embedlibc, and ch32v00x_startup.c
+
+
+
+// Use with newlib headers.
+// Mixture of weblibc, mini-printf and ???
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <stdint.h>
+#include <ch32v003fun.h>
+
+int errno;
+int _write(int fd, const char *buf, int size);
+
+int mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va);
+int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va);
+
+static int __puts_uart(char *s, int len, void *buf)
+{
+	_write( 0, s, len );
+	return len;
+}
+
+int printf(const char* format, ...)
+{
+	va_list args;
+	va_start( args, format );
+	int ret_status = mini_vpprintf(__puts_uart, 0, format, args);
+	va_end( args );
+	return ret_status;
+}
+
+
+/* Some stuff from MUSL
+
+
+----------------------------------------------------------------------
+Copyright © 2005-2020 Rich Felker, et al.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+----------------------------------------------------------------------
+
+*/
+
+/*
+ * mbstate_t is an opaque object to keep conversion state, during multibyte
+ * stream conversions.  The content must not be referenced by user programs.
+ */
+
+#define CURRENT_UTF8 0
+#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80)
+#define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1)
+
+typedef void * mbstate_t;
+
+size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st)
+{
+	if (!s) return 1;
+	if ((unsigned)wc < 0x80) {
+		*s = wc;
+		return 1;
+	} else if (MB_CUR_MAX == 1) {
+		if (!IS_CODEUNIT(wc)) {
+			errno = 0x02; // EILSEQ
+			return -1;
+		}
+		*s = wc;
+		return 1;
+	} else if ((unsigned)wc < 0x800) {
+		*s++ = 0xc0 | (wc>>6);
+		*s = 0x80 | (wc&0x3f);
+		return 2;
+	} else if ((unsigned)wc < 0xd800 || (unsigned)wc-0xe000 < 0x2000) {
+		*s++ = 0xe0 | (wc>>12);
+		*s++ = 0x80 | ((wc>>6)&0x3f);
+		*s = 0x80 | (wc&0x3f);
+		return 3;
+	} else if ((unsigned)wc-0x10000 < 0x100000) {
+		*s++ = 0xf0 | (wc>>18);
+		*s++ = 0x80 | ((wc>>12)&0x3f);
+		*s++ = 0x80 | ((wc>>6)&0x3f);
+		*s = 0x80 | (wc&0x3f);
+		return 4;
+	}
+	errno = 0x02;//EILSEQ;
+	return -1;
+}
+int wctomb(char *s, wchar_t wc)
+{
+	if (!s) return 0;
+	return wcrtomb(s, wc, 0);
+}
+size_t strlen(const char *s) { const char *a = s;for (; *s; s++);return s-a; }
+size_t strnlen(const char *s, size_t n) { const char *p = memchr(s, 0, n); return p ? p-s : n;}
+void *memset(void *dest, int c, size_t n) { unsigned char *s = dest; for (; n; n--, s++) *s = c; return dest; }
+char *strcpy(char *d, const char *s) { for (; (*d=*s); s++, d++); return d; }
+char *strncpy(char *d, const char *s, size_t n) { for (; n && (*d=*s); n--, s++, d++); return d; }
+int strcmp(const char *l, const char *r)
+{
+	for (; *l==*r && *l; l++, r++);
+	return *(unsigned char *)l - *(unsigned char *)r;
+}
+int strncmp(const char *_l, const char *_r, size_t n)
+{
+	const unsigned char *l=(void *)_l, *r=(void *)_r;
+	if (!n--) return 0;
+	for (; *l && *r && n && *l == *r ; l++, r++, n--);
+	return *l - *r;
+}
+
+static char *twobyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
+	for (h++; *h && hw != nw; hw = hw<<8 | *++h);
+	return *h ? (char *)h-1 : 0;
+}
+
+static char *threebyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8;
+	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8;
+	for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8);
+	return *h ? (char *)h-2 : 0;
+}
+
+static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n)
+{
+	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
+	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
+	for (h+=3; *h && hw != nw; hw = hw<<8 | *++h);
+	return *h ? (char *)h-3 : 0;
+}
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+static char *twoway_strstr(const unsigned char *h, const unsigned char *n)
+{
+	const unsigned char *z;
+	size_t l, ip, jp, k, p, ms, p0, mem, mem0;
+	size_t byteset[32 / sizeof(size_t)] = { 0 };
+	size_t shift[256];
+
+	/* Computing length of needle and fill shift table */
+	for (l=0; n[l] && h[l]; l++)
+		BITOP(byteset, n[l], |=), shift[n[l]] = l+1;
+	if (n[l]) return 0; /* hit the end of h */
+
+	/* Compute maximal suffix */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] > n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	ms = ip;
+	p0 = p;
+
+	/* And with the opposite comparison */
+	ip = -1; jp = 0; k = p = 1;
+	while (jp+k<l) {
+		if (n[ip+k] == n[jp+k]) {
+			if (k == p) {
+				jp += p;
+				k = 1;
+			} else k++;
+		} else if (n[ip+k] < n[jp+k]) {
+			jp += k;
+			k = 1;
+			p = jp - ip;
+		} else {
+			ip = jp++;
+			k = p = 1;
+		}
+	}
+	if (ip+1 > ms+1) ms = ip;
+	else p = p0;
+
+	/* Periodic needle? */
+	if (memcmp(n, n+p, ms+1)) {
+		mem0 = 0;
+		p = MAX(ms, l-ms-1) + 1;
+	} else mem0 = l-p;
+	mem = 0;
+
+	/* Initialize incremental end-of-haystack pointer */
+	z = h;
+
+	/* Search loop */
+	for (;;) {
+		/* Update incremental end-of-haystack pointer */
+		if (z-h < l) {
+			/* Fast estimate for MAX(l,63) */
+			size_t grow = l | 63;
+			const unsigned char *z2 = memchr(z, 0, grow);
+			if (z2) {
+				z = z2;
+				if (z-h < l) return 0;
+			} else z += grow;
+		}
+
+		/* Check last byte first; advance by shift on mismatch */
+		if (BITOP(byteset, h[l-1], &)) {
+			k = l-shift[h[l-1]];
+			if (k) {
+				if (k < mem) k = mem;
+				h += k;
+				mem = 0;
+				continue;
+			}
+		} else {
+			h += l;
+			mem = 0;
+			continue;
+		}
+
+		/* Compare right half */
+		for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++);
+		if (n[k]) {
+			h += k-ms;
+			mem = 0;
+			continue;
+		}
+		/* Compare left half */
+		for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
+		if (k <= mem) return (char *)h;
+		h += p;
+		mem = mem0;
+	}
+}
+
+char *strstr(const char *h, const char *n)
+{
+	/* Return immediately on empty needle */
+	if (!n[0]) return (char *)h;
+
+	/* Use faster algorithms for short needles */
+	h = strchr(h, *n);
+	if (!h || !n[1]) return (char *)h;
+	if (!h[1]) return 0;
+	if (!n[2]) return twobyte_strstr((void *)h, (void *)n);
+	if (!h[2]) return 0;
+	if (!n[3]) return threebyte_strstr((void *)h, (void *)n);
+	if (!h[3]) return 0;
+	if (!n[4]) return fourbyte_strstr((void *)h, (void *)n);
+
+	return twoway_strstr((void *)h, (void *)n);
+}
+
+char *strchr(const char *s, int c)
+{
+	c = (unsigned char)c;
+	if (!c) return (char *)s + strlen(s);
+	for (; *s && *(unsigned char *)s != c; s++);
+	return (char *)s;
+}
+
+
+void *__memrchr(const void *m, int c, size_t n)
+{
+	const unsigned char *s = m;
+	c = (unsigned char)c;
+	while (n--) if (s[n]==c) return (void *)(s+n);
+	return 0;
+}
+
+char *strrchr(const char *s, int c)
+{
+	return __memrchr(s, c, strlen(s) + 1);
+}
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+	unsigned char *d = dest;
+	const unsigned char *s = src;
+	for (; n; n--) *d++ = *s++;
+	return dest;
+}
+
+int memcmp(const void *vl, const void *vr, size_t n)
+{
+	const unsigned char *l=vl, *r=vr;
+	for (; n && *l == *r; n--, l++, r++);
+	return n ? *l-*r : 0;
+}
+
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+	char *d = dest;
+	const char *s = src;
+
+	if (d==s) return d;
+	if ((uintptr_t)s-(uintptr_t)d-n <= -2*n) return memcpy(d, s, n);
+
+	if (d<s) {
+		for (; n; n--) *d++ = *s++;
+	} else {
+		while (n) n--, d[n] = s[n];
+	}
+
+	return dest;
+}
+void *memchr(const void *src, int c, size_t n)
+{
+	const unsigned char *s = src;
+	c = (unsigned char)c;
+	for (; n && *s != c; s++, n--);
+	return n ? (void *)s : 0;
+}
+
+int puts(const char *s)
+{
+	int sl = strlen( s );
+	_write(0, s, sl );
+	_write(0, "\n", 1 );
+	return sl + 1;
+}
+
+/*
+ * The Minimal snprintf() implementation
+ *
+ * Copyright (c) 2013,2014 Michal Ludvig <michal@logix.cz>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the auhor nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----
+ *
+ * This is a minimal snprintf() implementation optimised
+ * for embedded systems with a very limited program memory.
+ * mini_snprintf() doesn't support _all_ the formatting
+ * the glibc does but on the other hand is a lot smaller.
+ * Here are some numbers from my STM32 project (.bin file size):
+ *      no snprintf():      10768 bytes
+ *      mini snprintf():    11420 bytes     (+  652 bytes)
+ *      glibc snprintf():   34860 bytes     (+24092 bytes)
+ * Wasting nearly 24kB of memory just for snprintf() on
+ * a chip with 32kB flash is crazy. Use mini_snprintf() instead.
+ *
+ */
+
+#define mini_strlen strlen
+
+static int
+mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
+	 char *buffer)
+{
+	char	*pbuffer = buffer;
+	int	negative = 0;
+	int	i, len;
+
+	/* No support for unusual radixes. */
+	if (radix > 16)
+		return 0;
+
+	if (value < 0 && !unsig) {
+		negative = 1;
+		value = -value;
+	}
+
+	/* This builds the string back to front ... */
+	do {
+		int digit = value % radix;
+		*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
+		value /= radix;
+	} while (value > 0);
+
+	if (negative)
+		*(pbuffer++) = '-';
+
+	*(pbuffer) = '\0';
+
+	/* ... now we reverse it (could do it recursively but will
+	 * conserve the stack space) */
+	len = (pbuffer - buffer);
+	for (i = 0; i < len / 2; i++) {
+		char j = buffer[i];
+		buffer[i] = buffer[len-i-1];
+		buffer[len-i-1] = j;
+	}
+
+	return len;
+}
+
+static int
+mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
+{
+	int i;
+	int overflow = 0;
+	char * pbuffer = buffer;
+	if(pad_to == 0) pad_to = len;
+	if(len > pad_to) {
+		len = pad_to;
+		overflow = 1;
+	}
+	for(i = pad_to - len; i > 0; i --) {
+		*(pbuffer++) = pad_char;
+	}
+	for(i = len; i > 0; i --) {
+		*(pbuffer++) = *(ptr++);
+	}
+	len = pbuffer - buffer;
+	if(overflow) {
+		for (i = 0; i < 3 && pbuffer > buffer; i ++) {
+			*(pbuffer-- - 1) = '*';
+		}
+	}
+	return len;
+}
+
+struct mini_buff {
+	char *buffer, *pbuffer;
+	unsigned int buffer_len;
+};
+
+static int
+_puts(char *s, int len, void *buf)
+{
+	if(!buf) return len;
+	struct mini_buff *b = buf;
+	char * p0 = b->buffer;
+	int i;
+	/* Copy to buffer */
+	for (i = 0; i < len; i++) {
+		if(b->pbuffer == b->buffer + b->buffer_len - 1) {
+			break;
+		}
+		*(b->pbuffer ++) = s[i];
+	}
+	*(b->pbuffer) = 0;
+	return b->pbuffer - p0;
+}
+
+#ifdef MINI_PRINTF_ENABLE_OBJECTS
+static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0;
+static void (*mini_handler_freeor)(void* data, void*) = 0;
+static void * mini_handler_data = 0;
+
+void mini_printf_set_handler(
+	void* data,
+	int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
+	void (*freeor)(void* data, void* buf))
+{
+	mini_handler = handler;
+	mini_handler_freeor = freeor;
+	mini_handler_data = data;
+}
+#endif
+
+int
+mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
+{
+	struct mini_buff b;
+	b.buffer = buffer;
+	b.pbuffer = buffer;
+	b.buffer_len = buffer_len;
+	if(buffer_len == 0) buffer = (void*) 0;
+	int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va);
+	if(buffer == (void*) 0) {
+		return n;
+	}
+	return b.pbuffer - b.buffer;
+}
+
+int
+mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
+{
+	char bf[24];
+	char bf2[24];
+	char ch;
+#ifdef MINI_PRINTF_ENABLE_OBJECTS
+	void* obj;
+#endif
+	if(puts == (void*)0) {
+		/* run puts in counting mode. */
+		puts = _puts; buf = (void*)0;
+	}
+	int n = 0;
+	while ((ch=*(fmt++))) {
+		int len;
+		if (ch!='%') {
+			len = 1;
+			len = puts(&ch, len, buf);
+		} else {
+			char pad_char = ' ';
+			int pad_to = 0;
+			char l = 0;
+			char *ptr;
+
+			ch=*(fmt++);
+
+			/* Zero padding requested */
+			if (ch == '0') pad_char = '0';
+			while (ch >= '0' && ch <= '9') {
+				pad_to = pad_to * 10 + (ch - '0');
+				ch=*(fmt++);
+			}
+			if(pad_to > (signed int) sizeof(bf)) {
+				pad_to = sizeof(bf);
+			}
+			if (ch == 'l') {
+				l = 1;
+				ch=*(fmt++);
+			}
+
+			switch (ch) {
+				case 0:
+					goto end;
+				case 'u':
+				case 'd':
+					if(l) {
+						len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2);
+					} else {
+						if(ch == 'u') {
+							len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2);
+						} else {
+							len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2);
+						}
+					}
+					len = mini_pad(bf2, len, pad_char, pad_to, bf);
+					len = puts(bf, len, buf);
+					break;
+
+				case 'x':
+				case 'X':
+					if(l) {
+						len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2);
+					} else {
+						len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2);
+					}
+					len = mini_pad(bf2, len, pad_char, pad_to, bf);
+					len = puts(bf, len, buf);
+					break;
+
+				case 'c' :
+					ch = (char)(va_arg(va, int));
+					len = mini_pad(&ch, 1, pad_char, pad_to, bf);
+					len = puts(bf, len, buf);
+					break;
+
+				case 's' :
+					ptr = va_arg(va, char*);
+					len = mini_strlen(ptr);
+					if (pad_to > 0) {
+						len = mini_pad(ptr, len, pad_char, pad_to, bf);
+						len = puts(bf, len, buf);
+					} else {
+						len = puts(ptr, len, buf);
+					}
+					break;
+#ifdef MINI_PRINTF_ENABLE_OBJECTS
+				case 'O' :  /* Object by content (e.g. str) */
+				case 'R' :  /* Object by representation (e.g. repr)*/
+					obj = va_arg(va, void*);
+					len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
+					if (pad_to > 0) {
+						len = mini_pad(ptr, len, pad_char, pad_to, bf);
+						len = puts(bf, len, buf);
+					} else {
+						len = puts(ptr, len, buf);
+					}
+					mini_handler_freeor(mini_handler_data, ptr);
+					break;
+#endif
+				default:
+					len = 1;
+					len = puts(&ch, len, buf);
+					break;
+			}
+		}
+		n = n + len;
+	}
+end:
+	return n;
+}
+
+
+int
+mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
+{
+	int ret;
+	va_list va;
+	va_start(va, fmt);
+	ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
+	va_end(va);
+
+	return ret;
+}
+
+int
+mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
+{
+	int ret;
+	va_list va;
+	va_start(va, fmt);
+	ret = mini_vpprintf(puts, buf, fmt, va);
+	va_end(va);
+
+	return ret;
+}
+
+
+/*
+	C version of CH32V003 Startup .s file from WCH
+	This file is public domain where possible or the following where not:
+	Copyright 2023 Charles Lohr, under the MIT-x11 or NewBSD licenses, you choose.
+*/
+
+
+int main() __attribute__((used));
+void SystemInit( void ) __attribute__((used));
+
+void InterruptVector()         __attribute__((naked)) __attribute((section(".init"))) __attribute__((used));
+void handle_reset()            __attribute__((naked)) __attribute((section(".text.handle_reset"))) __attribute__((used));
+void DefaultIRQHandler( void ) __attribute__((section(".text.vector_handler"))) __attribute__((naked)) __attribute__((used));
+
+extern uint32_t * _sbss;
+extern uint32_t * _ebss;
+extern uint32_t * _data_lma;
+extern uint32_t * _data_vma;
+extern uint32_t * _edata;
+
+
+// If you don't override a specific handler, it will just spin forever.
+void DefaultIRQHandler( void )
+{
+	// Infinite Loop
+	asm volatile( "1: j 1b" );
+}
+
+// This makes it so that all of the interrupt handlers just alias to
+// DefaultIRQHandler unless they are individually overridden.
+void NMI_Handler( void )                 __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void HardFault_Handler( void )           __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void SysTick_Handler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void SW_Handler( void )                  __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void WWDG_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void PVD_IRQHandler( void )              __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void FLASH_IRQHandler( void )            __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void RCC_IRQHandler( void )              __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void EXTI7_0_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void AWU_IRQHandler( void )              __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel1_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel2_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel3_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel4_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel5_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel6_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void DMA1_Channel7_IRQHandler( void )    __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void ADC1_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void I2C1_EV_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void I2C1_ER_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void USART1_IRQHandler( void )           __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void SPI1_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM1_BRK_IRQHandler( void )         __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM1_UP_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM1_TRG_COM_IRQHandler( void )     __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM1_CC_IRQHandler( void )          __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+void TIM2_IRQHandler( void )             __attribute__((section(".text.vector_handler"))) __attribute((weak,alias("DefaultIRQHandler"))) __attribute__((used));
+
+void InterruptVector()
+{
+	asm volatile( "\n\
+	.align  2\n\
+	.option   norvc;\n\
+	j handle_reset\n\
+	.word   0\n\
+	.word   NMI_Handler               /* NMI Handler */                    \n\
+	.word   HardFault_Handler         /* Hard Fault Handler */             \n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   0\n\
+	.word   SysTick_Handler           /* SysTick Handler */                \n\
+	.word   0\n\
+	.word   SW_Handler                /* SW Handler */                     \n\
+	.word   0\n\
+	/* External Interrupts */                                              \n\
+	.word   WWDG_IRQHandler           /* Window Watchdog */                \n\
+	.word   PVD_IRQHandler            /* PVD through EXTI Line detect */   \n\
+	.word   FLASH_IRQHandler          /* Flash */                          \n\
+	.word   RCC_IRQHandler            /* RCC */                            \n\
+	.word   EXTI7_0_IRQHandler        /* EXTI Line 7..0 */                 \n\
+	.word   AWU_IRQHandler            /* AWU */                            \n\
+	.word   DMA1_Channel1_IRQHandler  /* DMA1 Channel 1 */                 \n\
+	.word   DMA1_Channel2_IRQHandler  /* DMA1 Channel 2 */                 \n\
+	.word   DMA1_Channel3_IRQHandler  /* DMA1 Channel 3 */                 \n\
+	.word   DMA1_Channel4_IRQHandler  /* DMA1 Channel 4 */                 \n\
+	.word   DMA1_Channel5_IRQHandler  /* DMA1 Channel 5 */                 \n\
+	.word   DMA1_Channel6_IRQHandler  /* DMA1 Channel 6 */                 \n\
+	.word   DMA1_Channel7_IRQHandler  /* DMA1 Channel 7 */                 \n\
+	.word   ADC1_IRQHandler           /* ADC1 */                           \n\
+	.word   I2C1_EV_IRQHandler        /* I2C1 Event */                     \n\
+	.word   I2C1_ER_IRQHandler        /* I2C1 Error */                     \n\
+	.word   USART1_IRQHandler         /* USART1 */                         \n\
+	.word   SPI1_IRQHandler           /* SPI1 */                           \n\
+	.word   TIM1_BRK_IRQHandler       /* TIM1 Break */                     \n\
+	.word   TIM1_UP_IRQHandler        /* TIM1 Update */                    \n\
+	.word   TIM1_TRG_COM_IRQHandler   /* TIM1 Trigger and Commutation */   \n\
+	.word   TIM1_CC_IRQHandler        /* TIM1 Capture Compare */           \n\
+	.word   TIM2_IRQHandler           /* TIM2 */                           \n");
+}
+
+
+
+void handle_reset()
+{
+	asm volatile( "\n\
+.option push\n\
+.option norelax\n\
+	la gp, __global_pointer$\n\
+.option pop\n\
+	la sp, _eusrstack\n"
+	// Setup the interrupt vector, processor status and INTSYSCR.
+"	li t0, 0x80\n\
+	csrw mstatus, t0\n\
+	li t0, 0x3\n\
+	csrw 0x804, t0\n\
+	la t0, InterruptVector\n\
+	ori t0, t0, 3\n\
+	csrw mtvec, t0\n"
+ );
+
+	// Careful: Use registers to prevent overwriting of self-data.
+	// This clears out BSS.
+	register uint32_t * tempout = _sbss;
+	register uint32_t * tempend = _ebss;
+	while( tempout < tempend )
+		*(tempout++) = 0;
+
+	// Once we get here, it should be safe to execute regular C code.
+
+	// Load data section from flash to RAM 
+	register uint32_t * tempin = _data_lma;
+	tempout = _data_vma;
+	tempend = _edata;
+	while( tempout != tempend )
+		*(tempout++) = *(tempin++); 
+
+	asm volatile("csrw mepc, %0" : : "r"(main));
+
+	// set mepc to be main as the root app.
+	asm volatile( "mret\n" );
+}
+
+void SystemInit48HSI( void )
+{
+	// Values lifted from the EVT.  There is little to no documentation on what this does.
+	RCC->CTLR  = RCC_HSION | RCC_PLLON; 				// Use HSI, but enable PLL.
+	RCC->CFGR0 = RCC_HPRE_DIV1 | RCC_PLLSRC_HSI_Mul2;	// PLLCLK = HSI * 2 = 48 MHz; HCLK = SYSCLK = APB1
+	FLASH->ACTLR = FLASH_ACTLR_LATENCY_1;				// 1 Cycle Latency
+	RCC->INTR  = 0x009F0000;                            // Clear PLL, CSSC, HSE, HSI and LSI ready flags.
+
+	// From SetSysClockTo_48MHZ_HSI
+	while((RCC->CTLR & RCC_PLLRDY) == 0);														// Wait till PLL is ready
+	RCC->CFGR0 = ( RCC->CFGR0 & ((uint32_t)~(RCC_SW))) | (uint32_t)RCC_SW_PLL;					// Select PLL as system clock source
+	while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08);									// Wait till PLL is used as system clock source
+}
+
+void SetupUART( int uartBRR )
+{
+	// Enable GPIOD and UART.
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_USART1;
+
+	// Push-Pull, 10MHz Output, GPIO D5, with AutoFunction
+	GPIOD->CFGLR &= ~(0xf<<(4*5));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP_AF)<<(4*5);
+	
+	// 115200, 8n1.  Note if you don't specify a mode, UART remains off even when UE_Set.
+	USART1->CTLR1 = USART_WordLength_8b | USART_Parity_No | USART_Mode_Tx;
+	USART1->CTLR2 = USART_StopBits_1;
+	USART1->CTLR3 = USART_HardwareFlowControl_None;
+
+	USART1->BRR = uartBRR;
+	USART1->CTLR1 |= CTLR1_UE_Set;
+}
+
+
+// For debug writing to the UART.
+int _write(int fd, const char *buf, int size)
+{
+	for(int i = 0; i < size; i++){
+	    while( !(USART1->STATR & USART_FLAG_TC));
+	    USART1->DATAR = *buf++;
+	}
+	return size;
+}
+
+void DelaySysTick( uint32_t n )
+{
+    SysTick->SR &= ~(1 << 0);
+    SysTick->CMP = n;
+    SysTick->CNT = 0; 
+    SysTick->CTLR |=(1 << 0);
+    while(!(SysTick->SR & (1 << 0)));
+    SysTick->CTLR &= ~(1 << 0);
+}
diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h
new file mode 100644
index 0000000000000000000000000000000000000000..92ca4daeb4bb96b0b6dcffa2a28fdbf432b1b995
--- /dev/null
+++ b/ch32v003fun/ch32v003fun.h
@@ -0,0 +1,4848 @@
+// This contains a copy of ch32v00x.h and core_riscv.h ch32v00x_conf.h and other misc functions
+
+/********************************** (C) COPYRIGHT  *******************************
+ * File Name          : core_riscv.h
+ * Author             : WCH
+ * Version            : V1.0.0
+ * Date               : 2022/08/08
+ * Description        : RISC-V Core Peripheral Access Layer Header File
+ *********************************************************************************
+ * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+ * Attention: This software (modified or not) and binary are used for 
+ * microcontroller manufactured by Nanjing Qinheng Microelectronics.
+ *******************************************************************************/
+/*
+ * NOTE: This file modified by CNLohr to be fully-header-only.
+ */
+ 
+ 
+/* IO definitions */
+#ifdef __cplusplus
+  #define     __I     volatile                /*!< defines 'read only' permissions      */
+#else
+  #define     __I     volatile const          /*!< defines 'read only' permissions     */
+#endif
+#define     __O     volatile                  /*!< defines 'write only' permissions     */
+#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
+
+
+
+
+/********************************** (C) COPYRIGHT  *******************************
+ * File Name          : ch32v00x.h
+ * Author             : WCH
+ * Version            : V1.0.0
+ * Date               : 2022/08/08
+ * Description        : CH32V00x Device Peripheral Access Layer Header File.
+ *********************************************************************************
+ * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+ * Attention: This software (modified or not) and binary are used for 
+ * microcontroller manufactured by Nanjing Qinheng Microelectronics.
+ *******************************************************************************/
+#ifndef __CH32V00x_H
+#define __CH32V00x_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define __MPU_PRESENT             0  /* Other CH32 devices does not provide an MPU */
+#define __Vendor_SysTickConfig    0  /* Set to 1 if different SysTick Config is used */
+
+#define HSE_VALUE                 ((uint32_t)24000000) /* Value of the External oscillator in Hz */
+
+/* In the following line adjust the External High Speed oscillator (HSE) Startup Timeout value */
+#define HSE_STARTUP_TIMEOUT       ((uint16_t)0x2000) /* Time out for HSE start up */
+
+#define HSI_VALUE                 ((uint32_t)24000000) /* Value of the Internal oscillator in Hz */
+
+
+/* Interrupt Number Definition, according to the selected device */
+typedef enum IRQn
+{
+    /******  RISC-V Processor Exceptions Numbers *******************************************************/
+    NonMaskableInt_IRQn = 2, /* 2 Non Maskable Interrupt                             */
+    EXC_IRQn = 3,            /* 3 Exception Interrupt                                */
+    SysTicK_IRQn = 12,       /* 12 System timer Interrupt                            */
+    Software_IRQn = 14,      /* 14 software Interrupt                                */
+
+    /******  RISC-V specific Interrupt Numbers *********************************************************/
+    WWDG_IRQn = 16,          /* Window WatchDog Interrupt                            */
+    PVD_IRQn = 17,           /* PVD through EXTI Line detection Interrupt            */
+    FLASH_IRQn = 18,         /* FLASH global Interrupt                               */
+    RCC_IRQn = 19,           /* RCC global Interrupt                                 */
+    EXTI7_0_IRQn = 20,       /* External Line[7:0] Interrupts                        */
+    AWU_IRQn = 21,           /* AWU global Interrupt                                 */
+    DMA1_Channel1_IRQn = 22, /* DMA1 Channel 1 global Interrupt                      */
+    DMA1_Channel2_IRQn = 23, /* DMA1 Channel 2 global Interrupt                      */
+    DMA1_Channel3_IRQn = 24, /* DMA1 Channel 3 global Interrupt                      */
+    DMA1_Channel4_IRQn = 25, /* DMA1 Channel 4 global Interrupt                      */
+    DMA1_Channel5_IRQn = 26, /* DMA1 Channel 5 global Interrupt                      */
+    DMA1_Channel6_IRQn = 27, /* DMA1 Channel 6 global Interrupt                      */
+    DMA1_Channel7_IRQn = 28, /* DMA1 Channel 7 global Interrupt                      */
+    ADC_IRQn = 29,           /* ADC global Interrupt                                 */
+    I2C1_EV_IRQn = 30,       /* I2C1 Event Interrupt                                 */
+    I2C1_ER_IRQn = 31,       /* I2C1 Error Interrupt                                 */
+    USART1_IRQn = 32,        /* USART1 global Interrupt                              */
+    SPI1_IRQn = 33,          /* SPI1 global Interrupt                                */
+    TIM1_BRK_IRQn = 34,      /* TIM1 Break Interrupt                                 */
+    TIM1_UP_IRQn = 35,       /* TIM1 Update Interrupt                                */
+    TIM1_TRG_COM_IRQn = 36,  /* TIM1 Trigger and Commutation Interrupt               */
+    TIM1_CC_IRQn = 37,       /* TIM1 Capture Compare Interrupt                       */
+    TIM2_IRQn = 38,          /* TIM2 global Interrupt                                */
+
+} IRQn_Type;
+
+#define HardFault_IRQn    EXC_IRQn
+
+#include <stdint.h>
+
+/* Standard Peripheral Library old definitions (maintained for legacy purpose) */
+#define HSI_Value             HSI_VALUE
+#define HSE_Value             HSE_VALUE
+#define HSEStartUp_TimeOut    HSE_STARTUP_TIMEOUT
+
+/* Analog to Digital Converter */
+typedef struct
+{
+    __IO uint32_t STATR;
+    __IO uint32_t CTLR1;
+    __IO uint32_t CTLR2;
+    __IO uint32_t SAMPTR1;
+    __IO uint32_t SAMPTR2;
+    __IO uint32_t IOFR1;
+    __IO uint32_t IOFR2;
+    __IO uint32_t IOFR3;
+    __IO uint32_t IOFR4;
+    __IO uint32_t WDHTR;
+    __IO uint32_t WDLTR;
+    __IO uint32_t RSQR1;
+    __IO uint32_t RSQR2;
+    __IO uint32_t RSQR3;
+    __IO uint32_t ISQR;
+    __IO uint32_t IDATAR1;
+    __IO uint32_t IDATAR2;
+    __IO uint32_t IDATAR3;
+    __IO uint32_t IDATAR4;
+    __IO uint32_t RDATAR;
+    __IO uint32_t DLYR;
+} ADC_TypeDef;
+
+/* Debug MCU */
+typedef struct
+{
+    __IO uint32_t CFGR0;
+    __IO uint32_t CFGR1;
+} DBGMCU_TypeDef;
+
+/* DMA Controller */
+typedef struct
+{
+    __IO uint32_t CFGR;
+    __IO uint32_t CNTR;
+    __IO uint32_t PADDR;
+    __IO uint32_t MADDR;
+} DMA_Channel_TypeDef;
+
+typedef struct
+{
+    __IO uint32_t INTFR;
+    __IO uint32_t INTFCR;
+} DMA_TypeDef;
+
+/* External Interrupt/Event Controller */
+typedef struct
+{
+    __IO uint32_t INTENR;
+    __IO uint32_t EVENR;
+    __IO uint32_t RTENR;
+    __IO uint32_t FTENR;
+    __IO uint32_t SWIEVR;
+    __IO uint32_t INTFR;
+} EXTI_TypeDef;
+
+/* FLASH Registers */
+typedef struct
+{
+    __IO uint32_t ACTLR;
+    __IO uint32_t KEYR;
+    __IO uint32_t OBKEYR;
+    __IO uint32_t STATR;
+    __IO uint32_t CTLR;
+    __IO uint32_t ADDR;
+    __IO uint32_t RESERVED;
+    __IO uint32_t OBR;
+    __IO uint32_t WPR;
+    __IO uint32_t MODEKEYR;
+    __IO uint32_t BOOT_MODEKEYR;
+} FLASH_TypeDef;
+
+/* Option Bytes Registers */
+typedef struct
+{
+    __IO uint16_t RDPR;
+    __IO uint16_t USER;
+    __IO uint16_t Data0;
+    __IO uint16_t Data1;
+    __IO uint16_t WRPR0;
+    __IO uint16_t WRPR1;
+} OB_TypeDef;
+
+/* General Purpose I/O */
+typedef struct
+{
+    __IO uint32_t CFGLR;
+    __IO uint32_t CFGHR;
+    __IO uint32_t INDR;
+    __IO uint32_t OUTDR;
+    __IO uint32_t BSHR;
+    __IO uint32_t BCR;
+    __IO uint32_t LCKR;
+} GPIO_TypeDef;
+
+/* Alternate Function I/O */
+typedef struct
+{
+    uint32_t RESERVED0;
+    __IO uint32_t PCFR1;
+    __IO uint32_t EXTICR;
+} AFIO_TypeDef;
+
+/* Inter Integrated Circuit Interface */
+typedef struct
+{
+    __IO uint16_t CTLR1;
+    uint16_t      RESERVED0;
+    __IO uint16_t CTLR2;
+    uint16_t      RESERVED1;
+    __IO uint16_t OADDR1;
+    uint16_t      RESERVED2;
+    __IO uint16_t OADDR2;
+    uint16_t      RESERVED3;
+    __IO uint16_t DATAR;
+    uint16_t      RESERVED4;
+    __IO uint16_t STAR1;
+    uint16_t      RESERVED5;
+    __IO uint16_t STAR2;
+    uint16_t      RESERVED6;
+    __IO uint16_t CKCFGR;
+    uint16_t      RESERVED7;
+} I2C_TypeDef;
+
+/* Independent WatchDog */
+typedef struct
+{
+    __IO uint32_t CTLR;
+    __IO uint32_t PSCR;
+    __IO uint32_t RLDR;
+    __IO uint32_t STATR;
+} IWDG_TypeDef;
+
+/* Power Control */
+typedef struct
+{
+    __IO uint32_t CTLR;
+    __IO uint32_t CSR;
+    __IO uint32_t AWUCSR;
+    __IO uint32_t AWUWR;
+    __IO uint32_t AWUPSC;
+} PWR_TypeDef;
+
+/* Reset and Clock Control */
+typedef struct
+{
+    __IO uint32_t CTLR;
+    __IO uint32_t CFGR0;
+    __IO uint32_t INTR;
+    __IO uint32_t APB2PRSTR;
+    __IO uint32_t APB1PRSTR;
+    __IO uint32_t AHBPCENR;
+    __IO uint32_t APB2PCENR;
+    __IO uint32_t APB1PCENR;
+    __IO uint32_t RESERVED0;
+    __IO uint32_t RSTSCKR;
+} RCC_TypeDef;
+
+/* Serial Peripheral Interface */
+typedef struct
+{
+    __IO uint16_t CTLR1;
+    uint16_t      RESERVED0;
+    __IO uint16_t CTLR2;
+    uint16_t      RESERVED1;
+    __IO uint16_t STATR;
+    uint16_t      RESERVED2;
+    __IO uint16_t DATAR;
+    uint16_t      RESERVED3;
+    __IO uint16_t CRCR;
+    uint16_t      RESERVED4;
+    __IO uint16_t RCRCR;
+    uint16_t      RESERVED5;
+    __IO uint16_t TCRCR;
+    uint16_t      RESERVED6;
+    uint32_t      RESERVED7;
+    uint32_t      RESERVED8;
+    __IO uint16_t HSCR;
+    uint16_t      RESERVED9;
+} SPI_TypeDef;
+
+/* TIM */
+typedef struct
+{
+    __IO uint16_t CTLR1;
+    uint16_t      RESERVED0;
+    __IO uint16_t CTLR2;
+    uint16_t      RESERVED1;
+    __IO uint16_t SMCFGR;
+    uint16_t      RESERVED2;
+    __IO uint16_t DMAINTENR;
+    uint16_t      RESERVED3;
+    __IO uint16_t INTFR;
+    uint16_t      RESERVED4;
+    __IO uint16_t SWEVGR;
+    uint16_t      RESERVED5;
+    __IO uint16_t CHCTLR1;
+    uint16_t      RESERVED6;
+    __IO uint16_t CHCTLR2;
+    uint16_t      RESERVED7;
+    __IO uint16_t CCER;
+    uint16_t      RESERVED8;
+    __IO uint16_t CNT;
+    uint16_t      RESERVED9;
+    __IO uint16_t PSC;
+    uint16_t      RESERVED10;
+    __IO uint16_t ATRLR;
+    uint16_t      RESERVED11;
+    __IO uint16_t RPTCR;
+    uint16_t      RESERVED12;
+    __IO uint32_t CH1CVR;
+    __IO uint32_t CH2CVR;
+    __IO uint32_t CH3CVR;
+    __IO uint32_t CH4CVR;
+    __IO uint16_t BDTR;
+    uint16_t      RESERVED13;
+    __IO uint16_t DMACFGR;
+    uint16_t      RESERVED14;
+    __IO uint16_t DMAADR;
+    uint16_t      RESERVED15;
+} TIM_TypeDef;
+
+/* Universal Synchronous Asynchronous Receiver Transmitter */
+typedef struct
+{
+    __IO uint16_t STATR;
+    uint16_t      RESERVED0;
+    __IO uint16_t DATAR;
+    uint16_t      RESERVED1;
+    __IO uint16_t BRR;
+    uint16_t      RESERVED2;
+    __IO uint16_t CTLR1;
+    uint16_t      RESERVED3;
+    __IO uint16_t CTLR2;
+    uint16_t      RESERVED4;
+    __IO uint16_t CTLR3;
+    uint16_t      RESERVED5;
+    __IO uint16_t GPR;
+    uint16_t      RESERVED6;
+} USART_TypeDef;
+
+/* Window WatchDog */
+typedef struct
+{
+    __IO uint32_t CTLR;
+    __IO uint32_t CFGR;
+    __IO uint32_t STATR;
+} WWDG_TypeDef;
+
+/* Enhanced Registers */
+typedef struct
+{
+    __IO uint32_t EXTEN_CTR;
+} EXTEN_TypeDef;
+
+/* Peripheral memory map */
+#define FLASH_BASE                              ((uint32_t)0x08000000) /* FLASH base address in the alias region */
+#define SRAM_BASE                               ((uint32_t)0x20000000) /* SRAM base address in the alias region */
+#define PERIPH_BASE                             ((uint32_t)0x40000000) /* Peripheral base address in the alias region */
+
+#define APB1PERIPH_BASE                         (PERIPH_BASE)
+#define APB2PERIPH_BASE                         (PERIPH_BASE + 0x10000)
+#define AHBPERIPH_BASE                          (PERIPH_BASE + 0x20000)
+
+#define TIM2_BASE                               (APB1PERIPH_BASE + 0x0000)
+#define WWDG_BASE                               (APB1PERIPH_BASE + 0x2C00)
+#define IWDG_BASE                               (APB1PERIPH_BASE + 0x3000)
+#define I2C1_BASE                               (APB1PERIPH_BASE + 0x5400)
+#define PWR_BASE                                (APB1PERIPH_BASE + 0x7000)
+
+#define AFIO_BASE                               (APB2PERIPH_BASE + 0x0000)
+#define EXTI_BASE                               (APB2PERIPH_BASE + 0x0400)
+#define GPIOA_BASE                              (APB2PERIPH_BASE + 0x0800)
+#define GPIOC_BASE                              (APB2PERIPH_BASE + 0x1000)
+#define GPIOD_BASE                              (APB2PERIPH_BASE + 0x1400)
+#define ADC1_BASE                               (APB2PERIPH_BASE + 0x2400)
+#define TIM1_BASE                               (APB2PERIPH_BASE + 0x2C00)
+#define SPI1_BASE                               (APB2PERIPH_BASE + 0x3000)
+#define USART1_BASE                             (APB2PERIPH_BASE + 0x3800)
+
+#define DMA1_BASE                               (AHBPERIPH_BASE + 0x0000)
+#define DMA1_Channel1_BASE                      (AHBPERIPH_BASE + 0x0008)
+#define DMA1_Channel2_BASE                      (AHBPERIPH_BASE + 0x001C)
+#define DMA1_Channel3_BASE                      (AHBPERIPH_BASE + 0x0030)
+#define DMA1_Channel4_BASE                      (AHBPERIPH_BASE + 0x0044)
+#define DMA1_Channel5_BASE                      (AHBPERIPH_BASE + 0x0058)
+#define DMA1_Channel6_BASE                      (AHBPERIPH_BASE + 0x006C)
+#define DMA1_Channel7_BASE                      (AHBPERIPH_BASE + 0x0080)
+#define RCC_BASE                                (AHBPERIPH_BASE + 0x1000)
+
+#define FLASH_R_BASE                            (AHBPERIPH_BASE + 0x2000) /* Flash registers base address */
+#define OB_BASE                                 ((uint32_t)0x1FFFF800)    /* Flash Option Bytes base address */
+#define EXTEN_BASE                              ((uint32_t)0x40023800)
+
+/* Peripheral declaration */
+#define TIM2                                    ((TIM_TypeDef *)TIM2_BASE)
+#define WWDG                                    ((WWDG_TypeDef *)WWDG_BASE)
+#define IWDG                                    ((IWDG_TypeDef *)IWDG_BASE)
+#define I2C1                                    ((I2C_TypeDef *)I2C1_BASE)
+#define PWR                                     ((PWR_TypeDef *)PWR_BASE)
+#define AFIO                                    ((AFIO_TypeDef *)AFIO_BASE)
+#define EXTI                                    ((EXTI_TypeDef *)EXTI_BASE)
+#define GPIOA                                   ((GPIO_TypeDef *)GPIOA_BASE)
+#define GPIOC                                   ((GPIO_TypeDef *)GPIOC_BASE)
+#define GPIOD                                   ((GPIO_TypeDef *)GPIOD_BASE)
+#define ADC1                                    ((ADC_TypeDef *)ADC1_BASE)
+#define TIM1                                    ((TIM_TypeDef *)TIM1_BASE)
+#define SPI1                                    ((SPI_TypeDef *)SPI1_BASE)
+#define USART1                                  ((USART_TypeDef *)USART1_BASE)
+#define DMA1                                    ((DMA_TypeDef *)DMA1_BASE)
+#define DMA1_Channel1                           ((DMA_Channel_TypeDef *)DMA1_Channel1_BASE)
+#define DMA1_Channel2                           ((DMA_Channel_TypeDef *)DMA1_Channel2_BASE)
+#define DMA1_Channel3                           ((DMA_Channel_TypeDef *)DMA1_Channel3_BASE)
+#define DMA1_Channel4                           ((DMA_Channel_TypeDef *)DMA1_Channel4_BASE)
+#define DMA1_Channel5                           ((DMA_Channel_TypeDef *)DMA1_Channel5_BASE)
+#define DMA1_Channel6                           ((DMA_Channel_TypeDef *)DMA1_Channel6_BASE)
+#define DMA1_Channel7                           ((DMA_Channel_TypeDef *)DMA1_Channel7_BASE)
+#define RCC                                     ((RCC_TypeDef *)RCC_BASE)
+#define FLASH                                   ((FLASH_TypeDef *)FLASH_R_BASE)
+#define OB                                      ((OB_TypeDef *)OB_BASE)
+#define EXTEN                                   ((EXTEN_TypeDef *)EXTEN_BASE)
+
+/******************************************************************************/
+/*                         Peripheral Registers Bits Definition               */
+/******************************************************************************/
+
+/******************************************************************************/
+/*                        Analog to Digital Converter                         */
+/******************************************************************************/
+
+/********************  Bit definition for ADC_STATR register  ********************/
+#define ADC_AWD                                 ((uint8_t)0x01) /* Analog watchdog flag */
+#define ADC_EOC                                 ((uint8_t)0x02) /* End of conversion */
+#define ADC_JEOC                                ((uint8_t)0x04) /* Injected channel end of conversion */
+#define ADC_JSTRT                               ((uint8_t)0x08) /* Injected channel Start flag */
+#define ADC_STRT                                ((uint8_t)0x10) /* Regular channel Start flag */
+
+/*******************  Bit definition for ADC_CTLR1 register  ********************/
+#define ADC_AWDCH                               ((uint32_t)0x0000001F) /* AWDCH[4:0] bits (Analog watchdog channel select bits) */
+#define ADC_AWDCH_0                             ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_AWDCH_1                             ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_AWDCH_2                             ((uint32_t)0x00000004) /* Bit 2 */
+#define ADC_AWDCH_3                             ((uint32_t)0x00000008) /* Bit 3 */
+#define ADC_AWDCH_4                             ((uint32_t)0x00000010) /* Bit 4 */
+
+#define ADC_EOCIE                               ((uint32_t)0x00000020) /* Interrupt enable for EOC */
+#define ADC_AWDIE                               ((uint32_t)0x00000040) /* Analog Watchdog interrupt enable */
+#define ADC_JEOCIE                              ((uint32_t)0x00000080) /* Interrupt enable for injected channels */
+#define ADC_SCAN                                ((uint32_t)0x00000100) /* Scan mode */
+#define ADC_AWDSGL                              ((uint32_t)0x00000200) /* Enable the watchdog on a single channel in scan mode */
+#define ADC_JAUTO                               ((uint32_t)0x00000400) /* Automatic injected group conversion */
+#define ADC_DISCEN                              ((uint32_t)0x00000800) /* Discontinuous mode on regular channels */
+#define ADC_JDISCEN                             ((uint32_t)0x00001000) /* Discontinuous mode on injected channels */
+
+#define ADC_DISCNUM                             ((uint32_t)0x0000E000) /* DISCNUM[2:0] bits (Discontinuous mode channel count) */
+#define ADC_DISCNUM_0                           ((uint32_t)0x00002000) /* Bit 0 */
+#define ADC_DISCNUM_1                           ((uint32_t)0x00004000) /* Bit 1 */
+#define ADC_DISCNUM_2                           ((uint32_t)0x00008000) /* Bit 2 */
+
+#define ADC_DUALMOD                             ((uint32_t)0x000F0000) /* DUALMOD[3:0] bits (Dual mode selection) */
+#define ADC_DUALMOD_0                           ((uint32_t)0x00010000) /* Bit 0 */
+#define ADC_DUALMOD_1                           ((uint32_t)0x00020000) /* Bit 1 */
+#define ADC_DUALMOD_2                           ((uint32_t)0x00040000) /* Bit 2 */
+#define ADC_DUALMOD_3                           ((uint32_t)0x00080000) /* Bit 3 */
+
+#define ADC_JAWDEN                              ((uint32_t)0x00400000) /* Analog watchdog enable on injected channels */
+#define ADC_AWDEN                               ((uint32_t)0x00800000) /* Analog watchdog enable on regular channels */
+
+/*******************  Bit definition for ADC_CTLR2 register  ********************/
+#define ADC_ADON                                ((uint32_t)0x00000001) /* A/D Converter ON / OFF */
+#define ADC_CONT                                ((uint32_t)0x00000002) /* Continuous Conversion */
+#define ADC_CAL                                 ((uint32_t)0x00000004) /* A/D Calibration */
+#define ADC_RSTCAL                              ((uint32_t)0x00000008) /* Reset Calibration */
+#define ADC_DMA                                 ((uint32_t)0x00000100) /* Direct Memory access mode */
+#define ADC_ALIGN                               ((uint32_t)0x00000800) /* Data Alignment */
+
+#define ADC_JEXTSEL                             ((uint32_t)0x00007000) /* JEXTSEL[2:0] bits (External event select for injected group) */
+#define ADC_JEXTSEL_0                           ((uint32_t)0x00001000) /* Bit 0 */
+#define ADC_JEXTSEL_1                           ((uint32_t)0x00002000) /* Bit 1 */
+#define ADC_JEXTSEL_2                           ((uint32_t)0x00004000) /* Bit 2 */
+
+#define ADC_JEXTTRIG                            ((uint32_t)0x00008000) /* External Trigger Conversion mode for injected channels */
+
+#define ADC_EXTSEL                              ((uint32_t)0x000E0000) /* EXTSEL[2:0] bits (External Event Select for regular group) */
+#define ADC_EXTSEL_0                            ((uint32_t)0x00020000) /* Bit 0 */
+#define ADC_EXTSEL_1                            ((uint32_t)0x00040000) /* Bit 1 */
+#define ADC_EXTSEL_2                            ((uint32_t)0x00080000) /* Bit 2 */
+
+#define ADC_EXTTRIG                             ((uint32_t)0x00100000) /* External Trigger Conversion mode for regular channels */
+#define ADC_JSWSTART                            ((uint32_t)0x00200000) /* Start Conversion of injected channels */
+#define ADC_SWSTART                             ((uint32_t)0x00400000) /* Start Conversion of regular channels */
+#define ADC_TSVREFE                             ((uint32_t)0x00800000) /* Temperature Sensor and VREFINT Enable */
+
+/******************  Bit definition for ADC_SAMPTR1 register  *******************/
+#define ADC_SMP10                               ((uint32_t)0x00000007) /* SMP10[2:0] bits (Channel 10 Sample time selection) */
+#define ADC_SMP10_0                             ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_SMP10_1                             ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_SMP10_2                             ((uint32_t)0x00000004) /* Bit 2 */
+
+#define ADC_SMP11                               ((uint32_t)0x00000038) /* SMP11[2:0] bits (Channel 11 Sample time selection) */
+#define ADC_SMP11_0                             ((uint32_t)0x00000008) /* Bit 0 */
+#define ADC_SMP11_1                             ((uint32_t)0x00000010) /* Bit 1 */
+#define ADC_SMP11_2                             ((uint32_t)0x00000020) /* Bit 2 */
+
+#define ADC_SMP12                               ((uint32_t)0x000001C0) /* SMP12[2:0] bits (Channel 12 Sample time selection) */
+#define ADC_SMP12_0                             ((uint32_t)0x00000040) /* Bit 0 */
+#define ADC_SMP12_1                             ((uint32_t)0x00000080) /* Bit 1 */
+#define ADC_SMP12_2                             ((uint32_t)0x00000100) /* Bit 2 */
+
+#define ADC_SMP13                               ((uint32_t)0x00000E00) /* SMP13[2:0] bits (Channel 13 Sample time selection) */
+#define ADC_SMP13_0                             ((uint32_t)0x00000200) /* Bit 0 */
+#define ADC_SMP13_1                             ((uint32_t)0x00000400) /* Bit 1 */
+#define ADC_SMP13_2                             ((uint32_t)0x00000800) /* Bit 2 */
+
+#define ADC_SMP14                               ((uint32_t)0x00007000) /* SMP14[2:0] bits (Channel 14 Sample time selection) */
+#define ADC_SMP14_0                             ((uint32_t)0x00001000) /* Bit 0 */
+#define ADC_SMP14_1                             ((uint32_t)0x00002000) /* Bit 1 */
+#define ADC_SMP14_2                             ((uint32_t)0x00004000) /* Bit 2 */
+
+#define ADC_SMP15                               ((uint32_t)0x00038000) /* SMP15[2:0] bits (Channel 15 Sample time selection) */
+#define ADC_SMP15_0                             ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_SMP15_1                             ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_SMP15_2                             ((uint32_t)0x00020000) /* Bit 2 */
+
+#define ADC_SMP16                               ((uint32_t)0x001C0000) /* SMP16[2:0] bits (Channel 16 Sample time selection) */
+#define ADC_SMP16_0                             ((uint32_t)0x00040000) /* Bit 0 */
+#define ADC_SMP16_1                             ((uint32_t)0x00080000) /* Bit 1 */
+#define ADC_SMP16_2                             ((uint32_t)0x00100000) /* Bit 2 */
+
+#define ADC_SMP17                               ((uint32_t)0x00E00000) /* SMP17[2:0] bits (Channel 17 Sample time selection) */
+#define ADC_SMP17_0                             ((uint32_t)0x00200000) /* Bit 0 */
+#define ADC_SMP17_1                             ((uint32_t)0x00400000) /* Bit 1 */
+#define ADC_SMP17_2                             ((uint32_t)0x00800000) /* Bit 2 */
+
+/******************  Bit definition for ADC_SAMPTR2 register  *******************/
+#define ADC_SMP0                                ((uint32_t)0x00000007) /* SMP0[2:0] bits (Channel 0 Sample time selection) */
+#define ADC_SMP0_0                              ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_SMP0_1                              ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_SMP0_2                              ((uint32_t)0x00000004) /* Bit 2 */
+
+#define ADC_SMP1                                ((uint32_t)0x00000038) /* SMP1[2:0] bits (Channel 1 Sample time selection) */
+#define ADC_SMP1_0                              ((uint32_t)0x00000008) /* Bit 0 */
+#define ADC_SMP1_1                              ((uint32_t)0x00000010) /* Bit 1 */
+#define ADC_SMP1_2                              ((uint32_t)0x00000020) /* Bit 2 */
+
+#define ADC_SMP2                                ((uint32_t)0x000001C0) /* SMP2[2:0] bits (Channel 2 Sample time selection) */
+#define ADC_SMP2_0                              ((uint32_t)0x00000040) /* Bit 0 */
+#define ADC_SMP2_1                              ((uint32_t)0x00000080) /* Bit 1 */
+#define ADC_SMP2_2                              ((uint32_t)0x00000100) /* Bit 2 */
+
+#define ADC_SMP3                                ((uint32_t)0x00000E00) /* SMP3[2:0] bits (Channel 3 Sample time selection) */
+#define ADC_SMP3_0                              ((uint32_t)0x00000200) /* Bit 0 */
+#define ADC_SMP3_1                              ((uint32_t)0x00000400) /* Bit 1 */
+#define ADC_SMP3_2                              ((uint32_t)0x00000800) /* Bit 2 */
+
+#define ADC_SMP4                                ((uint32_t)0x00007000) /* SMP4[2:0] bits (Channel 4 Sample time selection) */
+#define ADC_SMP4_0                              ((uint32_t)0x00001000) /* Bit 0 */
+#define ADC_SMP4_1                              ((uint32_t)0x00002000) /* Bit 1 */
+#define ADC_SMP4_2                              ((uint32_t)0x00004000) /* Bit 2 */
+
+#define ADC_SMP5                                ((uint32_t)0x00038000) /* SMP5[2:0] bits (Channel 5 Sample time selection) */
+#define ADC_SMP5_0                              ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_SMP5_1                              ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_SMP5_2                              ((uint32_t)0x00020000) /* Bit 2 */
+
+#define ADC_SMP6                                ((uint32_t)0x001C0000) /* SMP6[2:0] bits (Channel 6 Sample time selection) */
+#define ADC_SMP6_0                              ((uint32_t)0x00040000) /* Bit 0 */
+#define ADC_SMP6_1                              ((uint32_t)0x00080000) /* Bit 1 */
+#define ADC_SMP6_2                              ((uint32_t)0x00100000) /* Bit 2 */
+
+#define ADC_SMP7                                ((uint32_t)0x00E00000) /* SMP7[2:0] bits (Channel 7 Sample time selection) */
+#define ADC_SMP7_0                              ((uint32_t)0x00200000) /* Bit 0 */
+#define ADC_SMP7_1                              ((uint32_t)0x00400000) /* Bit 1 */
+#define ADC_SMP7_2                              ((uint32_t)0x00800000) /* Bit 2 */
+
+#define ADC_SMP8                                ((uint32_t)0x07000000) /* SMP8[2:0] bits (Channel 8 Sample time selection) */
+#define ADC_SMP8_0                              ((uint32_t)0x01000000) /* Bit 0 */
+#define ADC_SMP8_1                              ((uint32_t)0x02000000) /* Bit 1 */
+#define ADC_SMP8_2                              ((uint32_t)0x04000000) /* Bit 2 */
+
+#define ADC_SMP9                                ((uint32_t)0x38000000) /* SMP9[2:0] bits (Channel 9 Sample time selection) */
+#define ADC_SMP9_0                              ((uint32_t)0x08000000) /* Bit 0 */
+#define ADC_SMP9_1                              ((uint32_t)0x10000000) /* Bit 1 */
+#define ADC_SMP9_2                              ((uint32_t)0x20000000) /* Bit 2 */
+
+/******************  Bit definition for ADC_IOFR1 register  *******************/
+#define ADC_JOFFSET1                            ((uint16_t)0x0FFF) /* Data offset for injected channel 1 */
+
+/******************  Bit definition for ADC_IOFR2 register  *******************/
+#define ADC_JOFFSET2                            ((uint16_t)0x0FFF) /* Data offset for injected channel 2 */
+
+/******************  Bit definition for ADC_IOFR3 register  *******************/
+#define ADC_JOFFSET3                            ((uint16_t)0x0FFF) /* Data offset for injected channel 3 */
+
+/******************  Bit definition for ADC_IOFR4 register  *******************/
+#define ADC_JOFFSET4                            ((uint16_t)0x0FFF) /* Data offset for injected channel 4 */
+
+/*******************  Bit definition for ADC_WDHTR register  ********************/
+#define ADC_HT                                  ((uint16_t)0x0FFF) /* Analog watchdog high threshold */
+
+/*******************  Bit definition for ADC_WDLTR register  ********************/
+#define ADC_LT                                  ((uint16_t)0x0FFF) /* Analog watchdog low threshold */
+
+/*******************  Bit definition for ADC_RSQR1 register  *******************/
+#define ADC_SQ13                                ((uint32_t)0x0000001F) /* SQ13[4:0] bits (13th conversion in regular sequence) */
+#define ADC_SQ13_0                              ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_SQ13_1                              ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_SQ13_2                              ((uint32_t)0x00000004) /* Bit 2 */
+#define ADC_SQ13_3                              ((uint32_t)0x00000008) /* Bit 3 */
+#define ADC_SQ13_4                              ((uint32_t)0x00000010) /* Bit 4 */
+
+#define ADC_SQ14                                ((uint32_t)0x000003E0) /* SQ14[4:0] bits (14th conversion in regular sequence) */
+#define ADC_SQ14_0                              ((uint32_t)0x00000020) /* Bit 0 */
+#define ADC_SQ14_1                              ((uint32_t)0x00000040) /* Bit 1 */
+#define ADC_SQ14_2                              ((uint32_t)0x00000080) /* Bit 2 */
+#define ADC_SQ14_3                              ((uint32_t)0x00000100) /* Bit 3 */
+#define ADC_SQ14_4                              ((uint32_t)0x00000200) /* Bit 4 */
+
+#define ADC_SQ15                                ((uint32_t)0x00007C00) /* SQ15[4:0] bits (15th conversion in regular sequence) */
+#define ADC_SQ15_0                              ((uint32_t)0x00000400) /* Bit 0 */
+#define ADC_SQ15_1                              ((uint32_t)0x00000800) /* Bit 1 */
+#define ADC_SQ15_2                              ((uint32_t)0x00001000) /* Bit 2 */
+#define ADC_SQ15_3                              ((uint32_t)0x00002000) /* Bit 3 */
+#define ADC_SQ15_4                              ((uint32_t)0x00004000) /* Bit 4 */
+
+#define ADC_SQ16                                ((uint32_t)0x000F8000) /* SQ16[4:0] bits (16th conversion in regular sequence) */
+#define ADC_SQ16_0                              ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_SQ16_1                              ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_SQ16_2                              ((uint32_t)0x00020000) /* Bit 2 */
+#define ADC_SQ16_3                              ((uint32_t)0x00040000) /* Bit 3 */
+#define ADC_SQ16_4                              ((uint32_t)0x00080000) /* Bit 4 */
+
+#define ADC_L                                   ((uint32_t)0x00F00000) /* L[3:0] bits (Regular channel sequence length) */
+#define ADC_L_0                                 ((uint32_t)0x00100000) /* Bit 0 */
+#define ADC_L_1                                 ((uint32_t)0x00200000) /* Bit 1 */
+#define ADC_L_2                                 ((uint32_t)0x00400000) /* Bit 2 */
+#define ADC_L_3                                 ((uint32_t)0x00800000) /* Bit 3 */
+
+/*******************  Bit definition for ADC_RSQR2 register  *******************/
+#define ADC_SQ7                                 ((uint32_t)0x0000001F) /* SQ7[4:0] bits (7th conversion in regular sequence) */
+#define ADC_SQ7_0                               ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_SQ7_1                               ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_SQ7_2                               ((uint32_t)0x00000004) /* Bit 2 */
+#define ADC_SQ7_3                               ((uint32_t)0x00000008) /* Bit 3 */
+#define ADC_SQ7_4                               ((uint32_t)0x00000010) /* Bit 4 */
+
+#define ADC_SQ8                                 ((uint32_t)0x000003E0) /* SQ8[4:0] bits (8th conversion in regular sequence) */
+#define ADC_SQ8_0                               ((uint32_t)0x00000020) /* Bit 0 */
+#define ADC_SQ8_1                               ((uint32_t)0x00000040) /* Bit 1 */
+#define ADC_SQ8_2                               ((uint32_t)0x00000080) /* Bit 2 */
+#define ADC_SQ8_3                               ((uint32_t)0x00000100) /* Bit 3 */
+#define ADC_SQ8_4                               ((uint32_t)0x00000200) /* Bit 4 */
+
+#define ADC_SQ9                                 ((uint32_t)0x00007C00) /* SQ9[4:0] bits (9th conversion in regular sequence) */
+#define ADC_SQ9_0                               ((uint32_t)0x00000400) /* Bit 0 */
+#define ADC_SQ9_1                               ((uint32_t)0x00000800) /* Bit 1 */
+#define ADC_SQ9_2                               ((uint32_t)0x00001000) /* Bit 2 */
+#define ADC_SQ9_3                               ((uint32_t)0x00002000) /* Bit 3 */
+#define ADC_SQ9_4                               ((uint32_t)0x00004000) /* Bit 4 */
+
+#define ADC_SQ10                                ((uint32_t)0x000F8000) /* SQ10[4:0] bits (10th conversion in regular sequence) */
+#define ADC_SQ10_0                              ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_SQ10_1                              ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_SQ10_2                              ((uint32_t)0x00020000) /* Bit 2 */
+#define ADC_SQ10_3                              ((uint32_t)0x00040000) /* Bit 3 */
+#define ADC_SQ10_4                              ((uint32_t)0x00080000) /* Bit 4 */
+
+#define ADC_SQ11                                ((uint32_t)0x01F00000) /* SQ11[4:0] bits (11th conversion in regular sequence) */
+#define ADC_SQ11_0                              ((uint32_t)0x00100000) /* Bit 0 */
+#define ADC_SQ11_1                              ((uint32_t)0x00200000) /* Bit 1 */
+#define ADC_SQ11_2                              ((uint32_t)0x00400000) /* Bit 2 */
+#define ADC_SQ11_3                              ((uint32_t)0x00800000) /* Bit 3 */
+#define ADC_SQ11_4                              ((uint32_t)0x01000000) /* Bit 4 */
+
+#define ADC_SQ12                                ((uint32_t)0x3E000000) /* SQ12[4:0] bits (12th conversion in regular sequence) */
+#define ADC_SQ12_0                              ((uint32_t)0x02000000) /* Bit 0 */
+#define ADC_SQ12_1                              ((uint32_t)0x04000000) /* Bit 1 */
+#define ADC_SQ12_2                              ((uint32_t)0x08000000) /* Bit 2 */
+#define ADC_SQ12_3                              ((uint32_t)0x10000000) /* Bit 3 */
+#define ADC_SQ12_4                              ((uint32_t)0x20000000) /* Bit 4 */
+
+/*******************  Bit definition for ADC_RSQR3 register  *******************/
+#define ADC_SQ1                                 ((uint32_t)0x0000001F) /* SQ1[4:0] bits (1st conversion in regular sequence) */
+#define ADC_SQ1_0                               ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_SQ1_1                               ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_SQ1_2                               ((uint32_t)0x00000004) /* Bit 2 */
+#define ADC_SQ1_3                               ((uint32_t)0x00000008) /* Bit 3 */
+#define ADC_SQ1_4                               ((uint32_t)0x00000010) /* Bit 4 */
+
+#define ADC_SQ2                                 ((uint32_t)0x000003E0) /* SQ2[4:0] bits (2nd conversion in regular sequence) */
+#define ADC_SQ2_0                               ((uint32_t)0x00000020) /* Bit 0 */
+#define ADC_SQ2_1                               ((uint32_t)0x00000040) /* Bit 1 */
+#define ADC_SQ2_2                               ((uint32_t)0x00000080) /* Bit 2 */
+#define ADC_SQ2_3                               ((uint32_t)0x00000100) /* Bit 3 */
+#define ADC_SQ2_4                               ((uint32_t)0x00000200) /* Bit 4 */
+
+#define ADC_SQ3                                 ((uint32_t)0x00007C00) /* SQ3[4:0] bits (3rd conversion in regular sequence) */
+#define ADC_SQ3_0                               ((uint32_t)0x00000400) /* Bit 0 */
+#define ADC_SQ3_1                               ((uint32_t)0x00000800) /* Bit 1 */
+#define ADC_SQ3_2                               ((uint32_t)0x00001000) /* Bit 2 */
+#define ADC_SQ3_3                               ((uint32_t)0x00002000) /* Bit 3 */
+#define ADC_SQ3_4                               ((uint32_t)0x00004000) /* Bit 4 */
+
+#define ADC_SQ4                                 ((uint32_t)0x000F8000) /* SQ4[4:0] bits (4th conversion in regular sequence) */
+#define ADC_SQ4_0                               ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_SQ4_1                               ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_SQ4_2                               ((uint32_t)0x00020000) /* Bit 2 */
+#define ADC_SQ4_3                               ((uint32_t)0x00040000) /* Bit 3 */
+#define ADC_SQ4_4                               ((uint32_t)0x00080000) /* Bit 4 */
+
+#define ADC_SQ5                                 ((uint32_t)0x01F00000) /* SQ5[4:0] bits (5th conversion in regular sequence) */
+#define ADC_SQ5_0                               ((uint32_t)0x00100000) /* Bit 0 */
+#define ADC_SQ5_1                               ((uint32_t)0x00200000) /* Bit 1 */
+#define ADC_SQ5_2                               ((uint32_t)0x00400000) /* Bit 2 */
+#define ADC_SQ5_3                               ((uint32_t)0x00800000) /* Bit 3 */
+#define ADC_SQ5_4                               ((uint32_t)0x01000000) /* Bit 4 */
+
+#define ADC_SQ6                                 ((uint32_t)0x3E000000) /* SQ6[4:0] bits (6th conversion in regular sequence) */
+#define ADC_SQ6_0                               ((uint32_t)0x02000000) /* Bit 0 */
+#define ADC_SQ6_1                               ((uint32_t)0x04000000) /* Bit 1 */
+#define ADC_SQ6_2                               ((uint32_t)0x08000000) /* Bit 2 */
+#define ADC_SQ6_3                               ((uint32_t)0x10000000) /* Bit 3 */
+#define ADC_SQ6_4                               ((uint32_t)0x20000000) /* Bit 4 */
+
+/*******************  Bit definition for ADC_ISQR register  *******************/
+#define ADC_JSQ1                                ((uint32_t)0x0000001F) /* JSQ1[4:0] bits (1st conversion in injected sequence) */
+#define ADC_JSQ1_0                              ((uint32_t)0x00000001) /* Bit 0 */
+#define ADC_JSQ1_1                              ((uint32_t)0x00000002) /* Bit 1 */
+#define ADC_JSQ1_2                              ((uint32_t)0x00000004) /* Bit 2 */
+#define ADC_JSQ1_3                              ((uint32_t)0x00000008) /* Bit 3 */
+#define ADC_JSQ1_4                              ((uint32_t)0x00000010) /* Bit 4 */
+
+#define ADC_JSQ2                                ((uint32_t)0x000003E0) /* JSQ2[4:0] bits (2nd conversion in injected sequence) */
+#define ADC_JSQ2_0                              ((uint32_t)0x00000020) /* Bit 0 */
+#define ADC_JSQ2_1                              ((uint32_t)0x00000040) /* Bit 1 */
+#define ADC_JSQ2_2                              ((uint32_t)0x00000080) /* Bit 2 */
+#define ADC_JSQ2_3                              ((uint32_t)0x00000100) /* Bit 3 */
+#define ADC_JSQ2_4                              ((uint32_t)0x00000200) /* Bit 4 */
+
+#define ADC_JSQ3                                ((uint32_t)0x00007C00) /* JSQ3[4:0] bits (3rd conversion in injected sequence) */
+#define ADC_JSQ3_0                              ((uint32_t)0x00000400) /* Bit 0 */
+#define ADC_JSQ3_1                              ((uint32_t)0x00000800) /* Bit 1 */
+#define ADC_JSQ3_2                              ((uint32_t)0x00001000) /* Bit 2 */
+#define ADC_JSQ3_3                              ((uint32_t)0x00002000) /* Bit 3 */
+#define ADC_JSQ3_4                              ((uint32_t)0x00004000) /* Bit 4 */
+
+#define ADC_JSQ4                                ((uint32_t)0x000F8000) /* JSQ4[4:0] bits (4th conversion in injected sequence) */
+#define ADC_JSQ4_0                              ((uint32_t)0x00008000) /* Bit 0 */
+#define ADC_JSQ4_1                              ((uint32_t)0x00010000) /* Bit 1 */
+#define ADC_JSQ4_2                              ((uint32_t)0x00020000) /* Bit 2 */
+#define ADC_JSQ4_3                              ((uint32_t)0x00040000) /* Bit 3 */
+#define ADC_JSQ4_4                              ((uint32_t)0x00080000) /* Bit 4 */
+
+#define ADC_JL                                  ((uint32_t)0x00300000) /* JL[1:0] bits (Injected Sequence length) */
+#define ADC_JL_0                                ((uint32_t)0x00100000) /* Bit 0 */
+#define ADC_JL_1                                ((uint32_t)0x00200000) /* Bit 1 */
+
+/*******************  Bit definition for ADC_IDATAR1 register  *******************/
+#define ADC_IDATAR1_JDATA                       ((uint16_t)0xFFFF) /* Injected data */
+
+/*******************  Bit definition for ADC_IDATAR2 register  *******************/
+#define ADC_IDATAR2_JDATA                       ((uint16_t)0xFFFF) /* Injected data */
+
+/*******************  Bit definition for ADC_IDATAR3 register  *******************/
+#define ADC_IDATAR3_JDATA                       ((uint16_t)0xFFFF) /* Injected data */
+
+/*******************  Bit definition for ADC_IDATAR4 register  *******************/
+#define ADC_IDATAR4_JDATA                       ((uint16_t)0xFFFF) /* Injected data */
+
+/********************  Bit definition for ADC_RDATAR register  ********************/
+#define ADC_RDATAR_DATA                         ((uint32_t)0x0000FFFF) /* Regular data */
+#define ADC_RDATAR_ADC2DATA                     ((uint32_t)0xFFFF0000) /* ADC2 data */
+
+/******************************************************************************/
+/*                             DMA Controller                                 */
+/******************************************************************************/
+
+/*******************  Bit definition for DMA_INTFR register  ********************/
+#define DMA_GIF1                                ((uint32_t)0x00000001) /* Channel 1 Global interrupt flag */
+#define DMA_TCIF1                               ((uint32_t)0x00000002) /* Channel 1 Transfer Complete flag */
+#define DMA_HTIF1                               ((uint32_t)0x00000004) /* Channel 1 Half Transfer flag */
+#define DMA_TEIF1                               ((uint32_t)0x00000008) /* Channel 1 Transfer Error flag */
+#define DMA_GIF2                                ((uint32_t)0x00000010) /* Channel 2 Global interrupt flag */
+#define DMA_TCIF2                               ((uint32_t)0x00000020) /* Channel 2 Transfer Complete flag */
+#define DMA_HTIF2                               ((uint32_t)0x00000040) /* Channel 2 Half Transfer flag */
+#define DMA_TEIF2                               ((uint32_t)0x00000080) /* Channel 2 Transfer Error flag */
+#define DMA_GIF3                                ((uint32_t)0x00000100) /* Channel 3 Global interrupt flag */
+#define DMA_TCIF3                               ((uint32_t)0x00000200) /* Channel 3 Transfer Complete flag */
+#define DMA_HTIF3                               ((uint32_t)0x00000400) /* Channel 3 Half Transfer flag */
+#define DMA_TEIF3                               ((uint32_t)0x00000800) /* Channel 3 Transfer Error flag */
+#define DMA_GIF4                                ((uint32_t)0x00001000) /* Channel 4 Global interrupt flag */
+#define DMA_TCIF4                               ((uint32_t)0x00002000) /* Channel 4 Transfer Complete flag */
+#define DMA_HTIF4                               ((uint32_t)0x00004000) /* Channel 4 Half Transfer flag */
+#define DMA_TEIF4                               ((uint32_t)0x00008000) /* Channel 4 Transfer Error flag */
+#define DMA_GIF5                                ((uint32_t)0x00010000) /* Channel 5 Global interrupt flag */
+#define DMA_TCIF5                               ((uint32_t)0x00020000) /* Channel 5 Transfer Complete flag */
+#define DMA_HTIF5                               ((uint32_t)0x00040000) /* Channel 5 Half Transfer flag */
+#define DMA_TEIF5                               ((uint32_t)0x00080000) /* Channel 5 Transfer Error flag */
+#define DMA_GIF6                                ((uint32_t)0x00100000) /* Channel 6 Global interrupt flag */
+#define DMA_TCIF6                               ((uint32_t)0x00200000) /* Channel 6 Transfer Complete flag */
+#define DMA_HTIF6                               ((uint32_t)0x00400000) /* Channel 6 Half Transfer flag */
+#define DMA_TEIF6                               ((uint32_t)0x00800000) /* Channel 6 Transfer Error flag */
+#define DMA_GIF7                                ((uint32_t)0x01000000) /* Channel 7 Global interrupt flag */
+#define DMA_TCIF7                               ((uint32_t)0x02000000) /* Channel 7 Transfer Complete flag */
+#define DMA_HTIF7                               ((uint32_t)0x04000000) /* Channel 7 Half Transfer flag */
+#define DMA_TEIF7                               ((uint32_t)0x08000000) /* Channel 7 Transfer Error flag */
+
+/*******************  Bit definition for DMA_INTFCR register  *******************/
+#define DMA_CGIF1                               ((uint32_t)0x00000001) /* Channel 1 Global interrupt clear */
+#define DMA_CTCIF1                              ((uint32_t)0x00000002) /* Channel 1 Transfer Complete clear */
+#define DMA_CHTIF1                              ((uint32_t)0x00000004) /* Channel 1 Half Transfer clear */
+#define DMA_CTEIF1                              ((uint32_t)0x00000008) /* Channel 1 Transfer Error clear */
+#define DMA_CGIF2                               ((uint32_t)0x00000010) /* Channel 2 Global interrupt clear */
+#define DMA_CTCIF2                              ((uint32_t)0x00000020) /* Channel 2 Transfer Complete clear */
+#define DMA_CHTIF2                              ((uint32_t)0x00000040) /* Channel 2 Half Transfer clear */
+#define DMA_CTEIF2                              ((uint32_t)0x00000080) /* Channel 2 Transfer Error clear */
+#define DMA_CGIF3                               ((uint32_t)0x00000100) /* Channel 3 Global interrupt clear */
+#define DMA_CTCIF3                              ((uint32_t)0x00000200) /* Channel 3 Transfer Complete clear */
+#define DMA_CHTIF3                              ((uint32_t)0x00000400) /* Channel 3 Half Transfer clear */
+#define DMA_CTEIF3                              ((uint32_t)0x00000800) /* Channel 3 Transfer Error clear */
+#define DMA_CGIF4                               ((uint32_t)0x00001000) /* Channel 4 Global interrupt clear */
+#define DMA_CTCIF4                              ((uint32_t)0x00002000) /* Channel 4 Transfer Complete clear */
+#define DMA_CHTIF4                              ((uint32_t)0x00004000) /* Channel 4 Half Transfer clear */
+#define DMA_CTEIF4                              ((uint32_t)0x00008000) /* Channel 4 Transfer Error clear */
+#define DMA_CGIF5                               ((uint32_t)0x00010000) /* Channel 5 Global interrupt clear */
+#define DMA_CTCIF5                              ((uint32_t)0x00020000) /* Channel 5 Transfer Complete clear */
+#define DMA_CHTIF5                              ((uint32_t)0x00040000) /* Channel 5 Half Transfer clear */
+#define DMA_CTEIF5                              ((uint32_t)0x00080000) /* Channel 5 Transfer Error clear */
+#define DMA_CGIF6                               ((uint32_t)0x00100000) /* Channel 6 Global interrupt clear */
+#define DMA_CTCIF6                              ((uint32_t)0x00200000) /* Channel 6 Transfer Complete clear */
+#define DMA_CHTIF6                              ((uint32_t)0x00400000) /* Channel 6 Half Transfer clear */
+#define DMA_CTEIF6                              ((uint32_t)0x00800000) /* Channel 6 Transfer Error clear */
+#define DMA_CGIF7                               ((uint32_t)0x01000000) /* Channel 7 Global interrupt clear */
+#define DMA_CTCIF7                              ((uint32_t)0x02000000) /* Channel 7 Transfer Complete clear */
+#define DMA_CHTIF7                              ((uint32_t)0x04000000) /* Channel 7 Half Transfer clear */
+#define DMA_CTEIF7                              ((uint32_t)0x08000000) /* Channel 7 Transfer Error clear */
+
+/*******************  Bit definition for DMA_CFGR1 register  *******************/
+#define DMA_CFGR1_EN                            ((uint16_t)0x0001) /* Channel enable*/
+#define DMA_CFGR1_TCIE                          ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFGR1_HTIE                          ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFGR1_TEIE                          ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFGR1_DIR                           ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFGR1_CIRC                          ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFGR1_PINC                          ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFGR1_MINC                          ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFGR1_PSIZE                         ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFGR1_PSIZE_0                       ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFGR1_PSIZE_1                       ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFGR1_MSIZE                         ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFGR1_MSIZE_0                       ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFGR1_MSIZE_1                       ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFGR1_PL                            ((uint16_t)0x3000) /* PL[1:0] bits(Channel Priority level) */
+#define DMA_CFGR1_PL_0                          ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFGR1_PL_1                          ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFGR1_MEM2MEM                       ((uint16_t)0x4000) /* Memory to memory mode */
+
+/*******************  Bit definition for DMA_CFGR2 register  *******************/
+#define DMA_CFGR2_EN                            ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFGR2_TCIE                          ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFGR2_HTIE                          ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFGR2_TEIE                          ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFGR2_DIR                           ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFGR2_CIRC                          ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFGR2_PINC                          ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFGR2_MINC                          ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFGR2_PSIZE                         ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFGR2_PSIZE_0                       ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFGR2_PSIZE_1                       ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFGR2_MSIZE                         ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFGR2_MSIZE_0                       ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFGR2_MSIZE_1                       ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFGR2_PL                            ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFGR2_PL_0                          ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFGR2_PL_1                          ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFGR2_MEM2MEM                       ((uint16_t)0x4000) /* Memory to memory mode */
+
+/*******************  Bit definition for DMA_CFGR3 register  *******************/
+#define DMA_CFGR3_EN                            ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFGR3_TCIE                          ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFGR3_HTIE                          ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFGR3_TEIE                          ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFGR3_DIR                           ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFGR3_CIRC                          ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFGR3_PINC                          ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFGR3_MINC                          ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFGR3_PSIZE                         ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFGR3_PSIZE_0                       ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFGR3_PSIZE_1                       ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFGR3_MSIZE                         ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFGR3_MSIZE_0                       ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFGR3_MSIZE_1                       ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFGR3_PL                            ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFGR3_PL_0                          ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFGR3_PL_1                          ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFGR3_MEM2MEM                       ((uint16_t)0x4000) /* Memory to memory mode */
+
+/*******************  Bit definition for DMA_CFG4 register  *******************/
+#define DMA_CFG4_EN                             ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFG4_TCIE                           ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFG4_HTIE                           ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFG4_TEIE                           ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFG4_DIR                            ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFG4_CIRC                           ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFG4_PINC                           ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFG4_MINC                           ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFG4_PSIZE                          ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFG4_PSIZE_0                        ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFG4_PSIZE_1                        ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFG4_MSIZE                          ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFG4_MSIZE_0                        ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFG4_MSIZE_1                        ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFG4_PL                             ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFG4_PL_0                           ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFG4_PL_1                           ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFG4_MEM2MEM                        ((uint16_t)0x4000) /* Memory to memory mode */
+
+/******************  Bit definition for DMA_CFG5 register  *******************/
+#define DMA_CFG5_EN                             ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFG5_TCIE                           ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFG5_HTIE                           ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFG5_TEIE                           ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFG5_DIR                            ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFG5_CIRC                           ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFG5_PINC                           ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFG5_MINC                           ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFG5_PSIZE                          ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFG5_PSIZE_0                        ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFG5_PSIZE_1                        ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFG5_MSIZE                          ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFG5_MSIZE_0                        ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFG5_MSIZE_1                        ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFG5_PL                             ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFG5_PL_0                           ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFG5_PL_1                           ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFG5_MEM2MEM                        ((uint16_t)0x4000) /* Memory to memory mode enable */
+
+/*******************  Bit definition for DMA_CFG6 register  *******************/
+#define DMA_CFG6_EN                             ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFG6_TCIE                           ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFG6_HTIE                           ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFG6_TEIE                           ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFG6_DIR                            ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFG6_CIRC                           ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFG6_PINC                           ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFG6_MINC                           ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFG6_PSIZE                          ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFG6_PSIZE_0                        ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFG6_PSIZE_1                        ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFG6_MSIZE                          ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFG6_MSIZE_0                        ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFG6_MSIZE_1                        ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFG6_PL                             ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFG6_PL_0                           ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFG6_PL_1                           ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFG6_MEM2MEM                        ((uint16_t)0x4000) /* Memory to memory mode */
+
+/*******************  Bit definition for DMA_CFG7 register  *******************/
+#define DMA_CFG7_EN                             ((uint16_t)0x0001) /* Channel enable */
+#define DMA_CFG7_TCIE                           ((uint16_t)0x0002) /* Transfer complete interrupt enable */
+#define DMA_CFG7_HTIE                           ((uint16_t)0x0004) /* Half Transfer interrupt enable */
+#define DMA_CFG7_TEIE                           ((uint16_t)0x0008) /* Transfer error interrupt enable */
+#define DMA_CFG7_DIR                            ((uint16_t)0x0010) /* Data transfer direction */
+#define DMA_CFG7_CIRC                           ((uint16_t)0x0020) /* Circular mode */
+#define DMA_CFG7_PINC                           ((uint16_t)0x0040) /* Peripheral increment mode */
+#define DMA_CFG7_MINC                           ((uint16_t)0x0080) /* Memory increment mode */
+
+#define DMA_CFG7_PSIZE                          ((uint16_t)0x0300) /* PSIZE[1:0] bits (Peripheral size) */
+#define DMA_CFG7_PSIZE_0                        ((uint16_t)0x0100) /* Bit 0 */
+#define DMA_CFG7_PSIZE_1                        ((uint16_t)0x0200) /* Bit 1 */
+
+#define DMA_CFG7_MSIZE                          ((uint16_t)0x0C00) /* MSIZE[1:0] bits (Memory size) */
+#define DMA_CFG7_MSIZE_0                        ((uint16_t)0x0400) /* Bit 0 */
+#define DMA_CFG7_MSIZE_1                        ((uint16_t)0x0800) /* Bit 1 */
+
+#define DMA_CFG7_PL                             ((uint16_t)0x3000) /* PL[1:0] bits (Channel Priority level) */
+#define DMA_CFG7_PL_0                           ((uint16_t)0x1000) /* Bit 0 */
+#define DMA_CFG7_PL_1                           ((uint16_t)0x2000) /* Bit 1 */
+
+#define DMA_CFG7_MEM2MEM                        ((uint16_t)0x4000) /* Memory to memory mode enable */
+
+/******************  Bit definition for DMA_CNTR1 register  ******************/
+#define DMA_CNTR1_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR2 register  ******************/
+#define DMA_CNTR2_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR3 register  ******************/
+#define DMA_CNTR3_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR4 register  ******************/
+#define DMA_CNTR4_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR5 register  ******************/
+#define DMA_CNTR5_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR6 register  ******************/
+#define DMA_CNTR6_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_CNTR7 register  ******************/
+#define DMA_CNTR7_NDT                           ((uint16_t)0xFFFF) /* Number of data to Transfer */
+
+/******************  Bit definition for DMA_PADDR1 register  *******************/
+#define DMA_PADDR1_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR2 register  *******************/
+#define DMA_PADDR2_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR3 register  *******************/
+#define DMA_PADDR3_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR4 register  *******************/
+#define DMA_PADDR4_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR5 register  *******************/
+#define DMA_PADDR5_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR6 register  *******************/
+#define DMA_PADDR6_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_PADDR7 register  *******************/
+#define DMA_PADDR7_PA                           ((uint32_t)0xFFFFFFFF) /* Peripheral Address */
+
+/******************  Bit definition for DMA_MADDR1 register  *******************/
+#define DMA_MADDR1_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR2 register  *******************/
+#define DMA_MADDR2_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR3 register  *******************/
+#define DMA_MADDR3_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR4 register  *******************/
+#define DMA_MADDR4_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR5 register  *******************/
+#define DMA_MADDR5_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR6 register  *******************/
+#define DMA_MADDR6_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************  Bit definition for DMA_MADDR7 register  *******************/
+#define DMA_MADDR7_MA                           ((uint32_t)0xFFFFFFFF) /* Memory Address */
+
+/******************************************************************************/
+/*                    External Interrupt/Event Controller                     */
+/******************************************************************************/
+
+/*******************  Bit definition for EXTI_INTENR register  *******************/
+#define EXTI_INTENR_MR0                         ((uint32_t)0x00000001) /* Interrupt Mask on line 0 */
+#define EXTI_INTENR_MR1                         ((uint32_t)0x00000002) /* Interrupt Mask on line 1 */
+#define EXTI_INTENR_MR2                         ((uint32_t)0x00000004) /* Interrupt Mask on line 2 */
+#define EXTI_INTENR_MR3                         ((uint32_t)0x00000008) /* Interrupt Mask on line 3 */
+#define EXTI_INTENR_MR4                         ((uint32_t)0x00000010) /* Interrupt Mask on line 4 */
+#define EXTI_INTENR_MR5                         ((uint32_t)0x00000020) /* Interrupt Mask on line 5 */
+#define EXTI_INTENR_MR6                         ((uint32_t)0x00000040) /* Interrupt Mask on line 6 */
+#define EXTI_INTENR_MR7                         ((uint32_t)0x00000080) /* Interrupt Mask on line 7 */
+#define EXTI_INTENR_MR8                         ((uint32_t)0x00000100) /* Interrupt Mask on line 8 */
+#define EXTI_INTENR_MR9                         ((uint32_t)0x00000200) /* Interrupt Mask on line 9 */
+
+/*******************  Bit definition for EXTI_EVENR register  *******************/
+#define EXTI_EVENR_MR0                          ((uint32_t)0x00000001) /* Event Mask on line 0 */
+#define EXTI_EVENR_MR1                          ((uint32_t)0x00000002) /* Event Mask on line 1 */
+#define EXTI_EVENR_MR2                          ((uint32_t)0x00000004) /* Event Mask on line 2 */
+#define EXTI_EVENR_MR3                          ((uint32_t)0x00000008) /* Event Mask on line 3 */
+#define EXTI_EVENR_MR4                          ((uint32_t)0x00000010) /* Event Mask on line 4 */
+#define EXTI_EVENR_MR5                          ((uint32_t)0x00000020) /* Event Mask on line 5 */
+#define EXTI_EVENR_MR6                          ((uint32_t)0x00000040) /* Event Mask on line 6 */
+#define EXTI_EVENR_MR7                          ((uint32_t)0x00000080) /* Event Mask on line 7 */
+#define EXTI_EVENR_MR8                          ((uint32_t)0x00000100) /* Event Mask on line 8 */
+#define EXTI_EVENR_MR9                          ((uint32_t)0x00000200) /* Event Mask on line 9 */
+
+/******************  Bit definition for EXTI_RTENR register  *******************/
+#define EXTI_RTENR_TR0                          ((uint32_t)0x00000001) /* Rising trigger event configuration bit of line 0 */
+#define EXTI_RTENR_TR1                          ((uint32_t)0x00000002) /* Rising trigger event configuration bit of line 1 */
+#define EXTI_RTENR_TR2                          ((uint32_t)0x00000004) /* Rising trigger event configuration bit of line 2 */
+#define EXTI_RTENR_TR3                          ((uint32_t)0x00000008) /* Rising trigger event configuration bit of line 3 */
+#define EXTI_RTENR_TR4                          ((uint32_t)0x00000010) /* Rising trigger event configuration bit of line 4 */
+#define EXTI_RTENR_TR5                          ((uint32_t)0x00000020) /* Rising trigger event configuration bit of line 5 */
+#define EXTI_RTENR_TR6                          ((uint32_t)0x00000040) /* Rising trigger event configuration bit of line 6 */
+#define EXTI_RTENR_TR7                          ((uint32_t)0x00000080) /* Rising trigger event configuration bit of line 7 */
+#define EXTI_RTENR_TR8                          ((uint32_t)0x00000100) /* Rising trigger event configuration bit of line 8 */
+#define EXTI_RTENR_TR9                          ((uint32_t)0x00000200) /* Rising trigger event configuration bit of line 9 */
+
+/******************  Bit definition for EXTI_FTENR register  *******************/
+#define EXTI_FTENR_TR0                          ((uint32_t)0x00000001) /* Falling trigger event configuration bit of line 0 */
+#define EXTI_FTENR_TR1                          ((uint32_t)0x00000002) /* Falling trigger event configuration bit of line 1 */
+#define EXTI_FTENR_TR2                          ((uint32_t)0x00000004) /* Falling trigger event configuration bit of line 2 */
+#define EXTI_FTENR_TR3                          ((uint32_t)0x00000008) /* Falling trigger event configuration bit of line 3 */
+#define EXTI_FTENR_TR4                          ((uint32_t)0x00000010) /* Falling trigger event configuration bit of line 4 */
+#define EXTI_FTENR_TR5                          ((uint32_t)0x00000020) /* Falling trigger event configuration bit of line 5 */
+#define EXTI_FTENR_TR6                          ((uint32_t)0x00000040) /* Falling trigger event configuration bit of line 6 */
+#define EXTI_FTENR_TR7                          ((uint32_t)0x00000080) /* Falling trigger event configuration bit of line 7 */
+#define EXTI_FTENR_TR8                          ((uint32_t)0x00000100) /* Falling trigger event configuration bit of line 8 */
+#define EXTI_FTENR_TR9                          ((uint32_t)0x00000200) /* Falling trigger event configuration bit of line 9 */
+
+/******************  Bit definition for EXTI_SWIEVR register  ******************/
+#define EXTI_SWIEVR_SWIEVR0                     ((uint32_t)0x00000001) /* Software Interrupt on line 0 */
+#define EXTI_SWIEVR_SWIEVR1                     ((uint32_t)0x00000002) /* Software Interrupt on line 1 */
+#define EXTI_SWIEVR_SWIEVR2                     ((uint32_t)0x00000004) /* Software Interrupt on line 2 */
+#define EXTI_SWIEVR_SWIEVR3                     ((uint32_t)0x00000008) /* Software Interrupt on line 3 */
+#define EXTI_SWIEVR_SWIEVR4                     ((uint32_t)0x00000010) /* Software Interrupt on line 4 */
+#define EXTI_SWIEVR_SWIEVR5                     ((uint32_t)0x00000020) /* Software Interrupt on line 5 */
+#define EXTI_SWIEVR_SWIEVR6                     ((uint32_t)0x00000040) /* Software Interrupt on line 6 */
+#define EXTI_SWIEVR_SWIEVR7                     ((uint32_t)0x00000080) /* Software Interrupt on line 7 */
+#define EXTI_SWIEVR_SWIEVR8                     ((uint32_t)0x00000100) /* Software Interrupt on line 8 */
+#define EXTI_SWIEVR_SWIEVR9                     ((uint32_t)0x00000200) /* Software Interrupt on line 9 */
+
+/*******************  Bit definition for EXTI_INTFR register  ********************/
+#define EXTI_INTF_INTF0                         ((uint32_t)0x00000001) /* Pending bit for line 0 */
+#define EXTI_INTF_INTF1                         ((uint32_t)0x00000002) /* Pending bit for line 1 */
+#define EXTI_INTF_INTF2                         ((uint32_t)0x00000004) /* Pending bit for line 2 */
+#define EXTI_INTF_INTF3                         ((uint32_t)0x00000008) /* Pending bit for line 3 */
+#define EXTI_INTF_INTF4                         ((uint32_t)0x00000010) /* Pending bit for line 4 */
+#define EXTI_INTF_INTF5                         ((uint32_t)0x00000020) /* Pending bit for line 5 */
+#define EXTI_INTF_INTF6                         ((uint32_t)0x00000040) /* Pending bit for line 6 */
+#define EXTI_INTF_INTF7                         ((uint32_t)0x00000080) /* Pending bit for line 7 */
+#define EXTI_INTF_INTF8                         ((uint32_t)0x00000100) /* Pending bit for line 8 */
+#define EXTI_INTF_INTF9                         ((uint32_t)0x00000200) /* Pending bit for line 9 */
+
+/******************************************************************************/
+/*                      FLASH and Option Bytes Registers                      */
+/******************************************************************************/
+
+/*******************  Bit definition for FLASH_ACTLR register  ******************/
+#define FLASH_ACTLR_LATENCY                     ((uint8_t)0x03) /* LATENCY[2:0] bits (Latency) */
+#define FLASH_ACTLR_LATENCY_0                   ((uint8_t)0x00) /* Bit 0 */
+#define FLASH_ACTLR_LATENCY_1                   ((uint8_t)0x01) /* Bit 0 */
+#define FLASH_ACTLR_LATENCY_2                   ((uint8_t)0x02) /* Bit 1 */
+
+/******************  Bit definition for FLASH_KEYR register  ******************/
+#define FLASH_KEYR_FKEYR                        ((uint32_t)0xFFFFFFFF) /* FPEC Key */
+
+/*****************  Bit definition for FLASH_OBKEYR register  ****************/
+#define FLASH_OBKEYR_OBKEYR                     ((uint32_t)0xFFFFFFFF) /* Option Byte Key */
+
+/******************  Bit definition for FLASH_STATR register  *******************/
+#define FLASH_STATR_BSY                         ((uint8_t)0x01) /* Busy */
+#define FLASH_STATR_WRPRTERR                    ((uint8_t)0x10) /* Write Protection Error */
+#define FLASH_STATR_EOP                         ((uint8_t)0x20) /* End of operation */
+
+/*******************  Bit definition for FLASH_CTLR register  *******************/
+#define FLASH_CTLR_PG                           ((uint16_t)0x0001)     /* Programming */
+#define FLASH_CTLR_PER                          ((uint16_t)0x0002)     /* Page Erase 1KByte*/
+#define FLASH_CTLR_MER                          ((uint16_t)0x0004)     /* Mass Erase */
+#define FLASH_CTLR_OPTPG                        ((uint16_t)0x0010)     /* Option Byte Programming */
+#define FLASH_CTLR_OPTER                        ((uint16_t)0x0020)     /* Option Byte Erase */
+#define FLASH_CTLR_STRT                         ((uint16_t)0x0040)     /* Start */
+#define FLASH_CTLR_LOCK                         ((uint16_t)0x0080)     /* Lock */
+#define FLASH_CTLR_OPTWRE                       ((uint16_t)0x0200)     /* Option Bytes Write Enable */
+#define FLASH_CTLR_ERRIE                        ((uint16_t)0x0400)     /* Error Interrupt Enable */
+#define FLASH_CTLR_EOPIE                        ((uint16_t)0x1000)     /* End of operation interrupt enable */
+#define FLASH_CTLR_PAGE_PG                      ((uint16_t)0x00010000) /* Page Programming 64Byte */
+#define FLASH_CTLR_PAGE_ER                      ((uint16_t)0x00020000) /* Page Erase 64Byte */
+#define FLASH_CTLR_BUF_LOAD                     ((uint16_t)0x00040000) /* Buffer Load */
+#define FLASH_CTLR_BUF_RST                      ((uint16_t)0x00080000) /* Buffer Reset */
+
+/*******************  Bit definition for FLASH_ADDR register  *******************/
+#define FLASH_ADDR_FAR                          ((uint32_t)0xFFFFFFFF) /* Flash Address */
+
+/******************  Bit definition for FLASH_OBR register  *******************/
+#define FLASH_OBR_OPTERR                        ((uint16_t)0x0001) /* Option Byte Error */
+#define FLASH_OBR_RDPRT                         ((uint16_t)0x0002) /* Read protection */
+
+#define FLASH_OBR_USER                          ((uint16_t)0x03FC) /* User Option Bytes */
+#define FLASH_OBR_WDG_SW                        ((uint16_t)0x0004) /* WDG_SW */
+#define FLASH_OBR_nRST_STOP                     ((uint16_t)0x0008) /* nRST_STOP */
+#define FLASH_OBR_nRST_STDBY                    ((uint16_t)0x0010) /* nRST_STDBY */
+#define FLASH_OBR_RST_MODE                      ((uint16_t)0x0060) /* RST_MODE */
+
+/******************  Bit definition for FLASH_WPR register  ******************/
+#define FLASH_WPR_WRP                           ((uint32_t)0xFFFFFFFF) /* Write Protect */
+
+/******************  Bit definition for FLASH_RDPR register  *******************/
+#define FLASH_RDPR_RDPR                         ((uint32_t)0x000000FF) /* Read protection option byte */
+#define FLASH_RDPR_nRDPR                        ((uint32_t)0x0000FF00) /* Read protection complemented option byte */
+
+/******************  Bit definition for FLASH_USER register  ******************/
+#define FLASH_USER_USER                         ((uint32_t)0x00FF0000) /* User option byte */
+#define FLASH_USER_nUSER                        ((uint32_t)0xFF000000) /* User complemented option byte */
+
+/******************  Bit definition for FLASH_Data0 register  *****************/
+#define FLASH_Data0_Data0                       ((uint32_t)0x000000FF) /* User data storage option byte */
+#define FLASH_Data0_nData0                      ((uint32_t)0x0000FF00) /* User data storage complemented option byte */
+
+/******************  Bit definition for FLASH_Data1 register  *****************/
+#define FLASH_Data1_Data1                       ((uint32_t)0x00FF0000) /* User data storage option byte */
+#define FLASH_Data1_nData1                      ((uint32_t)0xFF000000) /* User data storage complemented option byte */
+
+/******************  Bit definition for FLASH_WRPR0 register  ******************/
+#define FLASH_WRPR0_WRPR0                       ((uint32_t)0x000000FF) /* Flash memory write protection option bytes */
+#define FLASH_WRPR0_nWRPR0                      ((uint32_t)0x0000FF00) /* Flash memory write protection complemented option bytes */
+
+/******************  Bit definition for FLASH_WRPR1 register  ******************/
+#define FLASH_WRPR1_WRPR1                       ((uint32_t)0x00FF0000) /* Flash memory write protection option bytes */
+#define FLASH_WRPR1_nWRPR1                      ((uint32_t)0xFF000000) /* Flash memory write protection complemented option bytes */
+
+
+/******************************************************************************/
+/*                General Purpose and Alternate Function I/O                  */
+/******************************************************************************/
+
+/*******************  Bit definition for GPIO_CFGLR register  *******************/
+#define GPIO_CFGLR_MODE                         ((uint32_t)0x33333333) /* Port x mode bits */
+
+#define GPIO_CFGLR_MODE0                        ((uint32_t)0x00000003) /* MODE0[1:0] bits (Port x mode bits, pin 0) */
+#define GPIO_CFGLR_MODE0_0                      ((uint32_t)0x00000001) /* Bit 0 */
+#define GPIO_CFGLR_MODE0_1                      ((uint32_t)0x00000002) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE1                        ((uint32_t)0x00000030) /* MODE1[1:0] bits (Port x mode bits, pin 1) */
+#define GPIO_CFGLR_MODE1_0                      ((uint32_t)0x00000010) /* Bit 0 */
+#define GPIO_CFGLR_MODE1_1                      ((uint32_t)0x00000020) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE2                        ((uint32_t)0x00000300) /* MODE2[1:0] bits (Port x mode bits, pin 2) */
+#define GPIO_CFGLR_MODE2_0                      ((uint32_t)0x00000100) /* Bit 0 */
+#define GPIO_CFGLR_MODE2_1                      ((uint32_t)0x00000200) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE3                        ((uint32_t)0x00003000) /* MODE3[1:0] bits (Port x mode bits, pin 3) */
+#define GPIO_CFGLR_MODE3_0                      ((uint32_t)0x00001000) /* Bit 0 */
+#define GPIO_CFGLR_MODE3_1                      ((uint32_t)0x00002000) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE4                        ((uint32_t)0x00030000) /* MODE4[1:0] bits (Port x mode bits, pin 4) */
+#define GPIO_CFGLR_MODE4_0                      ((uint32_t)0x00010000) /* Bit 0 */
+#define GPIO_CFGLR_MODE4_1                      ((uint32_t)0x00020000) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE5                        ((uint32_t)0x00300000) /* MODE5[1:0] bits (Port x mode bits, pin 5) */
+#define GPIO_CFGLR_MODE5_0                      ((uint32_t)0x00100000) /* Bit 0 */
+#define GPIO_CFGLR_MODE5_1                      ((uint32_t)0x00200000) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE6                        ((uint32_t)0x03000000) /* MODE6[1:0] bits (Port x mode bits, pin 6) */
+#define GPIO_CFGLR_MODE6_0                      ((uint32_t)0x01000000) /* Bit 0 */
+#define GPIO_CFGLR_MODE6_1                      ((uint32_t)0x02000000) /* Bit 1 */
+
+#define GPIO_CFGLR_MODE7                        ((uint32_t)0x30000000) /* MODE7[1:0] bits (Port x mode bits, pin 7) */
+#define GPIO_CFGLR_MODE7_0                      ((uint32_t)0x10000000) /* Bit 0 */
+#define GPIO_CFGLR_MODE7_1                      ((uint32_t)0x20000000) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF                          ((uint32_t)0xCCCCCCCC) /* Port x configuration bits */
+
+#define GPIO_CFGLR_CNF0                         ((uint32_t)0x0000000C) /* CNF0[1:0] bits (Port x configuration bits, pin 0) */
+#define GPIO_CFGLR_CNF0_0                       ((uint32_t)0x00000004) /* Bit 0 */
+#define GPIO_CFGLR_CNF0_1                       ((uint32_t)0x00000008) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF1                         ((uint32_t)0x000000C0) /* CNF1[1:0] bits (Port x configuration bits, pin 1) */
+#define GPIO_CFGLR_CNF1_0                       ((uint32_t)0x00000040) /* Bit 0 */
+#define GPIO_CFGLR_CNF1_1                       ((uint32_t)0x00000080) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF2                         ((uint32_t)0x00000C00) /* CNF2[1:0] bits (Port x configuration bits, pin 2) */
+#define GPIO_CFGLR_CNF2_0                       ((uint32_t)0x00000400) /* Bit 0 */
+#define GPIO_CFGLR_CNF2_1                       ((uint32_t)0x00000800) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF3                         ((uint32_t)0x0000C000) /* CNF3[1:0] bits (Port x configuration bits, pin 3) */
+#define GPIO_CFGLR_CNF3_0                       ((uint32_t)0x00004000) /* Bit 0 */
+#define GPIO_CFGLR_CNF3_1                       ((uint32_t)0x00008000) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF4                         ((uint32_t)0x000C0000) /* CNF4[1:0] bits (Port x configuration bits, pin 4) */
+#define GPIO_CFGLR_CNF4_0                       ((uint32_t)0x00040000) /* Bit 0 */
+#define GPIO_CFGLR_CNF4_1                       ((uint32_t)0x00080000) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF5                         ((uint32_t)0x00C00000) /* CNF5[1:0] bits (Port x configuration bits, pin 5) */
+#define GPIO_CFGLR_CNF5_0                       ((uint32_t)0x00400000) /* Bit 0 */
+#define GPIO_CFGLR_CNF5_1                       ((uint32_t)0x00800000) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF6                         ((uint32_t)0x0C000000) /* CNF6[1:0] bits (Port x configuration bits, pin 6) */
+#define GPIO_CFGLR_CNF6_0                       ((uint32_t)0x04000000) /* Bit 0 */
+#define GPIO_CFGLR_CNF6_1                       ((uint32_t)0x08000000) /* Bit 1 */
+
+#define GPIO_CFGLR_CNF7                         ((uint32_t)0xC0000000) /* CNF7[1:0] bits (Port x configuration bits, pin 7) */
+#define GPIO_CFGLR_CNF7_0                       ((uint32_t)0x40000000) /* Bit 0 */
+#define GPIO_CFGLR_CNF7_1                       ((uint32_t)0x80000000) /* Bit 1 */
+
+/*******************  Bit definition for GPIO_CFGHR register  *******************/
+#define GPIO_CFGHR_MODE                         ((uint32_t)0x33333333) /* Port x mode bits */
+
+#define GPIO_CFGHR_MODE8                        ((uint32_t)0x00000003) /* MODE8[1:0] bits (Port x mode bits, pin 8) */
+#define GPIO_CFGHR_MODE8_0                      ((uint32_t)0x00000001) /* Bit 0 */
+#define GPIO_CFGHR_MODE8_1                      ((uint32_t)0x00000002) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE9                        ((uint32_t)0x00000030) /* MODE9[1:0] bits (Port x mode bits, pin 9) */
+#define GPIO_CFGHR_MODE9_0                      ((uint32_t)0x00000010) /* Bit 0 */
+#define GPIO_CFGHR_MODE9_1                      ((uint32_t)0x00000020) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE10                       ((uint32_t)0x00000300) /* MODE10[1:0] bits (Port x mode bits, pin 10) */
+#define GPIO_CFGHR_MODE10_0                     ((uint32_t)0x00000100) /* Bit 0 */
+#define GPIO_CFGHR_MODE10_1                     ((uint32_t)0x00000200) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE11                       ((uint32_t)0x00003000) /* MODE11[1:0] bits (Port x mode bits, pin 11) */
+#define GPIO_CFGHR_MODE11_0                     ((uint32_t)0x00001000) /* Bit 0 */
+#define GPIO_CFGHR_MODE11_1                     ((uint32_t)0x00002000) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE12                       ((uint32_t)0x00030000) /* MODE12[1:0] bits (Port x mode bits, pin 12) */
+#define GPIO_CFGHR_MODE12_0                     ((uint32_t)0x00010000) /* Bit 0 */
+#define GPIO_CFGHR_MODE12_1                     ((uint32_t)0x00020000) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE13                       ((uint32_t)0x00300000) /* MODE13[1:0] bits (Port x mode bits, pin 13) */
+#define GPIO_CFGHR_MODE13_0                     ((uint32_t)0x00100000) /* Bit 0 */
+#define GPIO_CFGHR_MODE13_1                     ((uint32_t)0x00200000) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE14                       ((uint32_t)0x03000000) /* MODE14[1:0] bits (Port x mode bits, pin 14) */
+#define GPIO_CFGHR_MODE14_0                     ((uint32_t)0x01000000) /* Bit 0 */
+#define GPIO_CFGHR_MODE14_1                     ((uint32_t)0x02000000) /* Bit 1 */
+
+#define GPIO_CFGHR_MODE15                       ((uint32_t)0x30000000) /* MODE15[1:0] bits (Port x mode bits, pin 15) */
+#define GPIO_CFGHR_MODE15_0                     ((uint32_t)0x10000000) /* Bit 0 */
+#define GPIO_CFGHR_MODE15_1                     ((uint32_t)0x20000000) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF                          ((uint32_t)0xCCCCCCCC) /* Port x configuration bits */
+
+#define GPIO_CFGHR_CNF8                         ((uint32_t)0x0000000C) /* CNF8[1:0] bits (Port x configuration bits, pin 8) */
+#define GPIO_CFGHR_CNF8_0                       ((uint32_t)0x00000004) /* Bit 0 */
+#define GPIO_CFGHR_CNF8_1                       ((uint32_t)0x00000008) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF9                         ((uint32_t)0x000000C0) /* CNF9[1:0] bits (Port x configuration bits, pin 9) */
+#define GPIO_CFGHR_CNF9_0                       ((uint32_t)0x00000040) /* Bit 0 */
+#define GPIO_CFGHR_CNF9_1                       ((uint32_t)0x00000080) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF10                        ((uint32_t)0x00000C00) /* CNF10[1:0] bits (Port x configuration bits, pin 10) */
+#define GPIO_CFGHR_CNF10_0                      ((uint32_t)0x00000400) /* Bit 0 */
+#define GPIO_CFGHR_CNF10_1                      ((uint32_t)0x00000800) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF11                        ((uint32_t)0x0000C000) /* CNF11[1:0] bits (Port x configuration bits, pin 11) */
+#define GPIO_CFGHR_CNF11_0                      ((uint32_t)0x00004000) /* Bit 0 */
+#define GPIO_CFGHR_CNF11_1                      ((uint32_t)0x00008000) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF12                        ((uint32_t)0x000C0000) /* CNF12[1:0] bits (Port x configuration bits, pin 12) */
+#define GPIO_CFGHR_CNF12_0                      ((uint32_t)0x00040000) /* Bit 0 */
+#define GPIO_CFGHR_CNF12_1                      ((uint32_t)0x00080000) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF13                        ((uint32_t)0x00C00000) /* CNF13[1:0] bits (Port x configuration bits, pin 13) */
+#define GPIO_CFGHR_CNF13_0                      ((uint32_t)0x00400000) /* Bit 0 */
+#define GPIO_CFGHR_CNF13_1                      ((uint32_t)0x00800000) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF14                        ((uint32_t)0x0C000000) /* CNF14[1:0] bits (Port x configuration bits, pin 14) */
+#define GPIO_CFGHR_CNF14_0                      ((uint32_t)0x04000000) /* Bit 0 */
+#define GPIO_CFGHR_CNF14_1                      ((uint32_t)0x08000000) /* Bit 1 */
+
+#define GPIO_CFGHR_CNF15                        ((uint32_t)0xC0000000) /* CNF15[1:0] bits (Port x configuration bits, pin 15) */
+#define GPIO_CFGHR_CNF15_0                      ((uint32_t)0x40000000) /* Bit 0 */
+#define GPIO_CFGHR_CNF15_1                      ((uint32_t)0x80000000) /* Bit 1 */
+
+/*******************  Bit definition for GPIO_INDR register  *******************/
+#define GPIO_INDR_IDR0                          ((uint16_t)0x0001) /* Port input data, bit 0 */
+#define GPIO_INDR_IDR1                          ((uint16_t)0x0002) /* Port input data, bit 1 */
+#define GPIO_INDR_IDR2                          ((uint16_t)0x0004) /* Port input data, bit 2 */
+#define GPIO_INDR_IDR3                          ((uint16_t)0x0008) /* Port input data, bit 3 */
+#define GPIO_INDR_IDR4                          ((uint16_t)0x0010) /* Port input data, bit 4 */
+#define GPIO_INDR_IDR5                          ((uint16_t)0x0020) /* Port input data, bit 5 */
+#define GPIO_INDR_IDR6                          ((uint16_t)0x0040) /* Port input data, bit 6 */
+#define GPIO_INDR_IDR7                          ((uint16_t)0x0080) /* Port input data, bit 7 */
+#define GPIO_INDR_IDR8                          ((uint16_t)0x0100) /* Port input data, bit 8 */
+#define GPIO_INDR_IDR9                          ((uint16_t)0x0200) /* Port input data, bit 9 */
+#define GPIO_INDR_IDR10                         ((uint16_t)0x0400) /* Port input data, bit 10 */
+#define GPIO_INDR_IDR11                         ((uint16_t)0x0800) /* Port input data, bit 11 */
+#define GPIO_INDR_IDR12                         ((uint16_t)0x1000) /* Port input data, bit 12 */
+#define GPIO_INDR_IDR13                         ((uint16_t)0x2000) /* Port input data, bit 13 */
+#define GPIO_INDR_IDR14                         ((uint16_t)0x4000) /* Port input data, bit 14 */
+#define GPIO_INDR_IDR15                         ((uint16_t)0x8000) /* Port input data, bit 15 */
+
+/*******************  Bit definition for GPIO_OUTDR register  *******************/
+#define GPIO_OUTDR_ODR0                         ((uint16_t)0x0001) /* Port output data, bit 0 */
+#define GPIO_OUTDR_ODR1                         ((uint16_t)0x0002) /* Port output data, bit 1 */
+#define GPIO_OUTDR_ODR2                         ((uint16_t)0x0004) /* Port output data, bit 2 */
+#define GPIO_OUTDR_ODR3                         ((uint16_t)0x0008) /* Port output data, bit 3 */
+#define GPIO_OUTDR_ODR4                         ((uint16_t)0x0010) /* Port output data, bit 4 */
+#define GPIO_OUTDR_ODR5                         ((uint16_t)0x0020) /* Port output data, bit 5 */
+#define GPIO_OUTDR_ODR6                         ((uint16_t)0x0040) /* Port output data, bit 6 */
+#define GPIO_OUTDR_ODR7                         ((uint16_t)0x0080) /* Port output data, bit 7 */
+#define GPIO_OUTDR_ODR8                         ((uint16_t)0x0100) /* Port output data, bit 8 */
+#define GPIO_OUTDR_ODR9                         ((uint16_t)0x0200) /* Port output data, bit 9 */
+#define GPIO_OUTDR_ODR10                        ((uint16_t)0x0400) /* Port output data, bit 10 */
+#define GPIO_OUTDR_ODR11                        ((uint16_t)0x0800) /* Port output data, bit 11 */
+#define GPIO_OUTDR_ODR12                        ((uint16_t)0x1000) /* Port output data, bit 12 */
+#define GPIO_OUTDR_ODR13                        ((uint16_t)0x2000) /* Port output data, bit 13 */
+#define GPIO_OUTDR_ODR14                        ((uint16_t)0x4000) /* Port output data, bit 14 */
+#define GPIO_OUTDR_ODR15                        ((uint16_t)0x8000) /* Port output data, bit 15 */
+
+/******************  Bit definition for GPIO_BSHR register  *******************/
+#define GPIO_BSHR_BS0                           ((uint32_t)0x00000001) /* Port x Set bit 0 */
+#define GPIO_BSHR_BS1                           ((uint32_t)0x00000002) /* Port x Set bit 1 */
+#define GPIO_BSHR_BS2                           ((uint32_t)0x00000004) /* Port x Set bit 2 */
+#define GPIO_BSHR_BS3                           ((uint32_t)0x00000008) /* Port x Set bit 3 */
+#define GPIO_BSHR_BS4                           ((uint32_t)0x00000010) /* Port x Set bit 4 */
+#define GPIO_BSHR_BS5                           ((uint32_t)0x00000020) /* Port x Set bit 5 */
+#define GPIO_BSHR_BS6                           ((uint32_t)0x00000040) /* Port x Set bit 6 */
+#define GPIO_BSHR_BS7                           ((uint32_t)0x00000080) /* Port x Set bit 7 */
+#define GPIO_BSHR_BS8                           ((uint32_t)0x00000100) /* Port x Set bit 8 */
+#define GPIO_BSHR_BS9                           ((uint32_t)0x00000200) /* Port x Set bit 9 */
+#define GPIO_BSHR_BS10                          ((uint32_t)0x00000400) /* Port x Set bit 10 */
+#define GPIO_BSHR_BS11                          ((uint32_t)0x00000800) /* Port x Set bit 11 */
+#define GPIO_BSHR_BS12                          ((uint32_t)0x00001000) /* Port x Set bit 12 */
+#define GPIO_BSHR_BS13                          ((uint32_t)0x00002000) /* Port x Set bit 13 */
+#define GPIO_BSHR_BS14                          ((uint32_t)0x00004000) /* Port x Set bit 14 */
+#define GPIO_BSHR_BS15                          ((uint32_t)0x00008000) /* Port x Set bit 15 */
+
+#define GPIO_BSHR_BR0                           ((uint32_t)0x00010000) /* Port x Reset bit 0 */
+#define GPIO_BSHR_BR1                           ((uint32_t)0x00020000) /* Port x Reset bit 1 */
+#define GPIO_BSHR_BR2                           ((uint32_t)0x00040000) /* Port x Reset bit 2 */
+#define GPIO_BSHR_BR3                           ((uint32_t)0x00080000) /* Port x Reset bit 3 */
+#define GPIO_BSHR_BR4                           ((uint32_t)0x00100000) /* Port x Reset bit 4 */
+#define GPIO_BSHR_BR5                           ((uint32_t)0x00200000) /* Port x Reset bit 5 */
+#define GPIO_BSHR_BR6                           ((uint32_t)0x00400000) /* Port x Reset bit 6 */
+#define GPIO_BSHR_BR7                           ((uint32_t)0x00800000) /* Port x Reset bit 7 */
+#define GPIO_BSHR_BR8                           ((uint32_t)0x01000000) /* Port x Reset bit 8 */
+#define GPIO_BSHR_BR9                           ((uint32_t)0x02000000) /* Port x Reset bit 9 */
+#define GPIO_BSHR_BR10                          ((uint32_t)0x04000000) /* Port x Reset bit 10 */
+#define GPIO_BSHR_BR11                          ((uint32_t)0x08000000) /* Port x Reset bit 11 */
+#define GPIO_BSHR_BR12                          ((uint32_t)0x10000000) /* Port x Reset bit 12 */
+#define GPIO_BSHR_BR13                          ((uint32_t)0x20000000) /* Port x Reset bit 13 */
+#define GPIO_BSHR_BR14                          ((uint32_t)0x40000000) /* Port x Reset bit 14 */
+#define GPIO_BSHR_BR15                          ((uint32_t)0x80000000) /* Port x Reset bit 15 */
+
+/*******************  Bit definition for GPIO_BCR register  *******************/
+#define GPIO_BCR_BR0                            ((uint16_t)0x0001) /* Port x Reset bit 0 */
+#define GPIO_BCR_BR1                            ((uint16_t)0x0002) /* Port x Reset bit 1 */
+#define GPIO_BCR_BR2                            ((uint16_t)0x0004) /* Port x Reset bit 2 */
+#define GPIO_BCR_BR3                            ((uint16_t)0x0008) /* Port x Reset bit 3 */
+#define GPIO_BCR_BR4                            ((uint16_t)0x0010) /* Port x Reset bit 4 */
+#define GPIO_BCR_BR5                            ((uint16_t)0x0020) /* Port x Reset bit 5 */
+#define GPIO_BCR_BR6                            ((uint16_t)0x0040) /* Port x Reset bit 6 */
+#define GPIO_BCR_BR7                            ((uint16_t)0x0080) /* Port x Reset bit 7 */
+#define GPIO_BCR_BR8                            ((uint16_t)0x0100) /* Port x Reset bit 8 */
+#define GPIO_BCR_BR9                            ((uint16_t)0x0200) /* Port x Reset bit 9 */
+#define GPIO_BCR_BR10                           ((uint16_t)0x0400) /* Port x Reset bit 10 */
+#define GPIO_BCR_BR11                           ((uint16_t)0x0800) /* Port x Reset bit 11 */
+#define GPIO_BCR_BR12                           ((uint16_t)0x1000) /* Port x Reset bit 12 */
+#define GPIO_BCR_BR13                           ((uint16_t)0x2000) /* Port x Reset bit 13 */
+#define GPIO_BCR_BR14                           ((uint16_t)0x4000) /* Port x Reset bit 14 */
+#define GPIO_BCR_BR15                           ((uint16_t)0x8000) /* Port x Reset bit 15 */
+
+/******************  Bit definition for GPIO_LCKR register  *******************/
+#define GPIO_LCK0                               ((uint32_t)0x00000001) /* Port x Lock bit 0 */
+#define GPIO_LCK1                               ((uint32_t)0x00000002) /* Port x Lock bit 1 */
+#define GPIO_LCK2                               ((uint32_t)0x00000004) /* Port x Lock bit 2 */
+#define GPIO_LCK3                               ((uint32_t)0x00000008) /* Port x Lock bit 3 */
+#define GPIO_LCK4                               ((uint32_t)0x00000010) /* Port x Lock bit 4 */
+#define GPIO_LCK5                               ((uint32_t)0x00000020) /* Port x Lock bit 5 */
+#define GPIO_LCK6                               ((uint32_t)0x00000040) /* Port x Lock bit 6 */
+#define GPIO_LCK7                               ((uint32_t)0x00000080) /* Port x Lock bit 7 */
+#define GPIO_LCK8                               ((uint32_t)0x00000100) /* Port x Lock bit 8 */
+#define GPIO_LCK9                               ((uint32_t)0x00000200) /* Port x Lock bit 9 */
+#define GPIO_LCK10                              ((uint32_t)0x00000400) /* Port x Lock bit 10 */
+#define GPIO_LCK11                              ((uint32_t)0x00000800) /* Port x Lock bit 11 */
+#define GPIO_LCK12                              ((uint32_t)0x00001000) /* Port x Lock bit 12 */
+#define GPIO_LCK13                              ((uint32_t)0x00002000) /* Port x Lock bit 13 */
+#define GPIO_LCK14                              ((uint32_t)0x00004000) /* Port x Lock bit 14 */
+#define GPIO_LCK15                              ((uint32_t)0x00008000) /* Port x Lock bit 15 */
+#define GPIO_LCKK                               ((uint32_t)0x00010000) /* Lock key */
+
+/******************  Bit definition for AFIO_PCFR1register  *******************/
+#define AFIO_PCFR1_SPI1_REMAP                   ((uint32_t)0x00000001) /* SPI1 remapping */
+#define AFIO_PCFR1_I2C1_REMAP                   ((uint32_t)0x00000002) /* I2C1 remapping */
+#define AFIO_PCFR1_USART1_REMAP                 ((uint32_t)0x00000004) /* USART1 remapping */
+#define AFIO_PCFR1_USART2_REMAP                 ((uint32_t)0x00000008) /* USART2 remapping */
+
+#define AFIO_PCFR1_USART3_REMAP                 ((uint32_t)0x00000030) /* USART3_REMAP[1:0] bits (USART3 remapping) */
+#define AFIO_PCFR1_USART3_REMAP_0               ((uint32_t)0x00000010) /* Bit 0 */
+#define AFIO_PCFR1_USART3_REMAP_1               ((uint32_t)0x00000020) /* Bit 1 */
+
+#define AFIO_PCFR1_USART3_REMAP_NOREMAP         ((uint32_t)0x00000000) /* No remap (TX/PB10, RX/PB11, CK/PB12, CTS/PB13, RTS/PB14) */
+#define AFIO_PCFR1_USART3_REMAP_PARTIALREMAP    ((uint32_t)0x00000010) /* Partial remap (TX/PC10, RX/PC11, CK/PC12, CTS/PB13, RTS/PB14) */
+#define AFIO_PCFR1_USART3_REMAP_FULLREMAP       ((uint32_t)0x00000030) /* Full remap (TX/PD8, RX/PD9, CK/PD10, CTS/PD11, RTS/PD12) */
+
+#define AFIO_PCFR1_TIM1_REMAP                   ((uint32_t)0x000000C0) /* TIM1_REMAP[1:0] bits (TIM1 remapping) */
+#define AFIO_PCFR1_TIM1_REMAP_0                 ((uint32_t)0x00000040) /* Bit 0 */
+#define AFIO_PCFR1_TIM1_REMAP_1                 ((uint32_t)0x00000080) /* Bit 1 */
+
+#define AFIO_PCFR1_TIM1_REMAP_NOREMAP           ((uint32_t)0x00000000) /* No remap (ETR/PA12, CH1/PA8, CH2/PA9, CH3/PA10, CH4/PA11, BKIN/PB12, CH1N/PB13, CH2N/PB14, CH3N/PB15) */
+#define AFIO_PCFR1_TIM1_REMAP_PARTIALREMAP      ((uint32_t)0x00000040) /* Partial remap (ETR/PA12, CH1/PA8, CH2/PA9, CH3/PA10, CH4/PA11, BKIN/PA6, CH1N/PA7, CH2N/PB0, CH3N/PB1) */
+#define AFIO_PCFR1_TIM1_REMAP_FULLREMAP         ((uint32_t)0x000000C0) /* Full remap (ETR/PE7, CH1/PE9, CH2/PE11, CH3/PE13, CH4/PE14, BKIN/PE15, CH1N/PE8, CH2N/PE10, CH3N/PE12) */
+
+#define AFIO_PCFR1_TIM2_REMAP                   ((uint32_t)0x00000300) /* TIM2_REMAP[1:0] bits (TIM2 remapping) */
+#define AFIO_PCFR1_TIM2_REMAP_0                 ((uint32_t)0x00000100) /* Bit 0 */
+#define AFIO_PCFR1_TIM2_REMAP_1                 ((uint32_t)0x00000200) /* Bit 1 */
+
+#define AFIO_PCFR1_TIM2_REMAP_NOREMAP           ((uint32_t)0x00000000) /* No remap (CH1/ETR/PA0, CH2/PA1, CH3/PA2, CH4/PA3) */
+#define AFIO_PCFR1_TIM2_REMAP_PARTIALREMAP1     ((uint32_t)0x00000100) /* Partial remap (CH1/ETR/PA15, CH2/PB3, CH3/PA2, CH4/PA3) */
+#define AFIO_PCFR1_TIM2_REMAP_PARTIALREMAP2     ((uint32_t)0x00000200) /* Partial remap (CH1/ETR/PA0, CH2/PA1, CH3/PB10, CH4/PB11) */
+#define AFIO_PCFR1_TIM2_REMAP_FULLREMAP         ((uint32_t)0x00000300) /* Full remap (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11) */
+
+#define AFIO_PCFR1_TIM3_REMAP                   ((uint32_t)0x00000C00) /* TIM3_REMAP[1:0] bits (TIM3 remapping) */
+#define AFIO_PCFR1_TIM3_REMAP_0                 ((uint32_t)0x00000400) /* Bit 0 */
+#define AFIO_PCFR1_TIM3_REMAP_1                 ((uint32_t)0x00000800) /* Bit 1 */
+
+#define AFIO_PCFR1_TIM3_REMAP_NOREMAP           ((uint32_t)0x00000000) /* No remap (CH1/PA6, CH2/PA7, CH3/PB0, CH4/PB1) */
+#define AFIO_PCFR1_TIM3_REMAP_PARTIALREMAP      ((uint32_t)0x00000800) /* Partial remap (CH1/PB4, CH2/PB5, CH3/PB0, CH4/PB1) */
+#define AFIO_PCFR1_TIM3_REMAP_FULLREMAP         ((uint32_t)0x00000C00) /* Full remap (CH1/PC6, CH2/PC7, CH3/PC8, CH4/PC9) */
+
+#define AFIO_PCFR1_TIM4_REMAP                   ((uint32_t)0x00001000) /* TIM4_REMAP bit (TIM4 remapping) */
+
+#define AFIO_PCFR1_CAN_REMAP                    ((uint32_t)0x00006000) /* CAN_REMAP[1:0] bits (CAN Alternate function remapping) */
+#define AFIO_PCFR1_CAN_REMAP_0                  ((uint32_t)0x00002000) /* Bit 0 */
+#define AFIO_PCFR1_CAN_REMAP_1                  ((uint32_t)0x00004000) /* Bit 1 */
+
+#define AFIO_PCFR1_CAN_REMAP_REMAP1             ((uint32_t)0x00000000) /* CANRX mapped to PA11, CANTX mapped to PA12 */
+#define AFIO_PCFR1_CAN_REMAP_REMAP2             ((uint32_t)0x00004000) /* CANRX mapped to PB8, CANTX mapped to PB9 */
+#define AFIO_PCFR1_CAN_REMAP_REMAP3             ((uint32_t)0x00006000) /* CANRX mapped to PD0, CANTX mapped to PD1 */
+
+#define AFIO_PCFR1_PA12_REMAP                   ((uint32_t)0x00008000) /* Port D0/Port D1 mapping on OSC_IN/OSC_OUT */
+#define AFIO_PCFR1_TIM5CH4_IREMAP               ((uint32_t)0x00010000) /* TIM5 Channel4 Internal Remap */
+#define AFIO_PCFR1_ADC1_ETRGINJ_REMAP           ((uint32_t)0x00020000) /* ADC 1 External Trigger Injected Conversion remapping */
+#define AFIO_PCFR1_ADC1_ETRGREG_REMAP           ((uint32_t)0x00040000) /* ADC 1 External Trigger Regular Conversion remapping */
+#define AFIO_PCFR1_ADC2_ETRGINJ_REMAP           ((uint32_t)0x00080000) /* ADC 2 External Trigger Injected Conversion remapping */
+#define AFIO_PCFR1_ADC2_ETRGREG_REMAP           ((uint32_t)0x00100000) /* ADC 2 External Trigger Regular Conversion remapping */
+
+#define AFIO_PCFR1_SWJ_CFG                      ((uint32_t)0x07000000) /* SWJ_CFG[2:0] bits (Serial Wire JTAG configuration) */
+#define AFIO_PCFR1_SWJ_CFG_0                    ((uint32_t)0x01000000) /* Bit 0 */
+#define AFIO_PCFR1_SWJ_CFG_1                    ((uint32_t)0x02000000) /* Bit 1 */
+#define AFIO_PCFR1_SWJ_CFG_2                    ((uint32_t)0x04000000) /* Bit 2 */
+
+#define AFIO_PCFR1_SWJ_CFG_RESET                ((uint32_t)0x00000000) /* Full SWJ (JTAG-DP + SW-DP) : Reset State */
+#define AFIO_PCFR1_SWJ_CFG_NOJNTRST             ((uint32_t)0x01000000) /* Full SWJ (JTAG-DP + SW-DP) but without JNTRST */
+#define AFIO_PCFR1_SWJ_CFG_JTAGDISABLE          ((uint32_t)0x02000000) /* JTAG-DP Disabled and SW-DP Enabled */
+#define AFIO_PCFR1_SWJ_CFG_DISABLE              ((uint32_t)0x04000000) /* JTAG-DP Disabled and SW-DP Disabled */
+
+/*****************  Bit definition for AFIO_EXTICR1 register  *****************/
+#define AFIO_EXTICR1_EXTI0                      ((uint16_t)0x000F) /* EXTI 0 configuration */
+#define AFIO_EXTICR1_EXTI1                      ((uint16_t)0x00F0) /* EXTI 1 configuration */
+#define AFIO_EXTICR1_EXTI2                      ((uint16_t)0x0F00) /* EXTI 2 configuration */
+#define AFIO_EXTICR1_EXTI3                      ((uint16_t)0xF000) /* EXTI 3 configuration */
+
+#define AFIO_EXTICR1_EXTI0_PA                   ((uint16_t)0x0000) /* PA[0] pin */
+#define AFIO_EXTICR1_EXTI0_PB                   ((uint16_t)0x0001) /* PB[0] pin */
+#define AFIO_EXTICR1_EXTI0_PC                   ((uint16_t)0x0002) /* PC[0] pin */
+#define AFIO_EXTICR1_EXTI0_PD                   ((uint16_t)0x0003) /* PD[0] pin */
+#define AFIO_EXTICR1_EXTI0_PE                   ((uint16_t)0x0004) /* PE[0] pin */
+#define AFIO_EXTICR1_EXTI0_PF                   ((uint16_t)0x0005) /* PF[0] pin */
+#define AFIO_EXTICR1_EXTI0_PG                   ((uint16_t)0x0006) /* PG[0] pin */
+
+#define AFIO_EXTICR1_EXTI1_PA                   ((uint16_t)0x0000) /* PA[1] pin */
+#define AFIO_EXTICR1_EXTI1_PB                   ((uint16_t)0x0010) /* PB[1] pin */
+#define AFIO_EXTICR1_EXTI1_PC                   ((uint16_t)0x0020) /* PC[1] pin */
+#define AFIO_EXTICR1_EXTI1_PD                   ((uint16_t)0x0030) /* PD[1] pin */
+#define AFIO_EXTICR1_EXTI1_PE                   ((uint16_t)0x0040) /* PE[1] pin */
+#define AFIO_EXTICR1_EXTI1_PF                   ((uint16_t)0x0050) /* PF[1] pin */
+#define AFIO_EXTICR1_EXTI1_PG                   ((uint16_t)0x0060) /* PG[1] pin */
+
+#define AFIO_EXTICR1_EXTI2_PA                   ((uint16_t)0x0000) /* PA[2] pin */
+#define AFIO_EXTICR1_EXTI2_PB                   ((uint16_t)0x0100) /* PB[2] pin */
+#define AFIO_EXTICR1_EXTI2_PC                   ((uint16_t)0x0200) /* PC[2] pin */
+#define AFIO_EXTICR1_EXTI2_PD                   ((uint16_t)0x0300) /* PD[2] pin */
+#define AFIO_EXTICR1_EXTI2_PE                   ((uint16_t)0x0400) /* PE[2] pin */
+#define AFIO_EXTICR1_EXTI2_PF                   ((uint16_t)0x0500) /* PF[2] pin */
+#define AFIO_EXTICR1_EXTI2_PG                   ((uint16_t)0x0600) /* PG[2] pin */
+
+#define AFIO_EXTICR1_EXTI3_PA                   ((uint16_t)0x0000) /* PA[3] pin */
+#define AFIO_EXTICR1_EXTI3_PB                   ((uint16_t)0x1000) /* PB[3] pin */
+#define AFIO_EXTICR1_EXTI3_PC                   ((uint16_t)0x2000) /* PC[3] pin */
+#define AFIO_EXTICR1_EXTI3_PD                   ((uint16_t)0x3000) /* PD[3] pin */
+#define AFIO_EXTICR1_EXTI3_PE                   ((uint16_t)0x4000) /* PE[3] pin */
+#define AFIO_EXTICR1_EXTI3_PF                   ((uint16_t)0x5000) /* PF[3] pin */
+#define AFIO_EXTICR1_EXTI3_PG                   ((uint16_t)0x6000) /* PG[3] pin */
+
+/******************************************************************************/
+/*                           Independent WATCHDOG                             */
+/******************************************************************************/
+
+/*******************  Bit definition for IWDG_CTLR register  ********************/
+#define IWDG_KEY                                ((uint16_t)0xFFFF) /* Key value (write only, read 0000h) */
+
+/*******************  Bit definition for IWDG_PSCR register  ********************/
+#define IWDG_PR                                 ((uint8_t)0x07) /* PR[2:0] (Prescaler divider) */
+#define IWDG_PR_0                               ((uint8_t)0x01) /* Bit 0 */
+#define IWDG_PR_1                               ((uint8_t)0x02) /* Bit 1 */
+#define IWDG_PR_2                               ((uint8_t)0x04) /* Bit 2 */
+
+/*******************  Bit definition for IWDG_RLDR register  *******************/
+#define IWDG_RL                                 ((uint16_t)0x0FFF) /* Watchdog counter reload value */
+
+/*******************  Bit definition for IWDG_STATR register  ********************/
+#define IWDG_PVU                                ((uint8_t)0x01) /* Watchdog prescaler value update */
+#define IWDG_RVU                                ((uint8_t)0x02) /* Watchdog counter reload value update */
+
+/******************************************************************************/
+/*                      Inter-integrated Circuit Interface                    */
+/******************************************************************************/
+
+/*******************  Bit definition for I2C_CTLR1 register  ********************/
+#define I2C_CTLR1_PE                            ((uint16_t)0x0001) /* Peripheral Enable */
+#define I2C_CTLR1_SMBUS                         ((uint16_t)0x0002) /* SMBus Mode */
+#define I2C_CTLR1_SMBTYPE                       ((uint16_t)0x0008) /* SMBus Type */
+#define I2C_CTLR1_ENARP                         ((uint16_t)0x0010) /* ARP Enable */
+#define I2C_CTLR1_ENPEC                         ((uint16_t)0x0020) /* PEC Enable */
+#define I2C_CTLR1_ENGC                          ((uint16_t)0x0040) /* General Call Enable */
+#define I2C_CTLR1_NOSTRETCH                     ((uint16_t)0x0080) /* Clock Stretching Disable (Slave mode) */
+#define I2C_CTLR1_START                         ((uint16_t)0x0100) /* Start Generation */
+#define I2C_CTLR1_STOP                          ((uint16_t)0x0200) /* Stop Generation */
+#define I2C_CTLR1_ACK                           ((uint16_t)0x0400) /* Acknowledge Enable */
+#define I2C_CTLR1_POS                           ((uint16_t)0x0800) /* Acknowledge/PEC Position (for data reception) */
+#define I2C_CTLR1_PEC                           ((uint16_t)0x1000) /* Packet Error Checking */
+#define I2C_CTLR1_ALERT                         ((uint16_t)0x2000) /* SMBus Alert */
+#define I2C_CTLR1_SWRST                         ((uint16_t)0x8000) /* Software Reset */
+
+/*******************  Bit definition for I2C_CTLR2 register  ********************/
+#define I2C_CTLR2_FREQ                          ((uint16_t)0x003F) /* FREQ[5:0] bits (Peripheral Clock Frequency) */
+#define I2C_CTLR2_FREQ_0                        ((uint16_t)0x0001) /* Bit 0 */
+#define I2C_CTLR2_FREQ_1                        ((uint16_t)0x0002) /* Bit 1 */
+#define I2C_CTLR2_FREQ_2                        ((uint16_t)0x0004) /* Bit 2 */
+#define I2C_CTLR2_FREQ_3                        ((uint16_t)0x0008) /* Bit 3 */
+#define I2C_CTLR2_FREQ_4                        ((uint16_t)0x0010) /* Bit 4 */
+#define I2C_CTLR2_FREQ_5                        ((uint16_t)0x0020) /* Bit 5 */
+
+#define I2C_CTLR2_ITERREN                       ((uint16_t)0x0100) /* Error Interrupt Enable */
+#define I2C_CTLR2_ITEVTEN                       ((uint16_t)0x0200) /* Event Interrupt Enable */
+#define I2C_CTLR2_ITBUFEN                       ((uint16_t)0x0400) /* Buffer Interrupt Enable */
+#define I2C_CTLR2_DMAEN                         ((uint16_t)0x0800) /* DMA Requests Enable */
+#define I2C_CTLR2_LAST                          ((uint16_t)0x1000) /* DMA Last Transfer */
+
+/*******************  Bit definition for I2C_OADDR1 register  *******************/
+#define I2C_OADDR1_ADD1_7                       ((uint16_t)0x00FE) /* Interface Address */
+#define I2C_OADDR1_ADD8_9                       ((uint16_t)0x0300) /* Interface Address */
+
+#define I2C_OADDR1_ADD0                         ((uint16_t)0x0001) /* Bit 0 */
+#define I2C_OADDR1_ADD1                         ((uint16_t)0x0002) /* Bit 1 */
+#define I2C_OADDR1_ADD2                         ((uint16_t)0x0004) /* Bit 2 */
+#define I2C_OADDR1_ADD3                         ((uint16_t)0x0008) /* Bit 3 */
+#define I2C_OADDR1_ADD4                         ((uint16_t)0x0010) /* Bit 4 */
+#define I2C_OADDR1_ADD5                         ((uint16_t)0x0020) /* Bit 5 */
+#define I2C_OADDR1_ADD6                         ((uint16_t)0x0040) /* Bit 6 */
+#define I2C_OADDR1_ADD7                         ((uint16_t)0x0080) /* Bit 7 */
+#define I2C_OADDR1_ADD8                         ((uint16_t)0x0100) /* Bit 8 */
+#define I2C_OADDR1_ADD9                         ((uint16_t)0x0200) /* Bit 9 */
+
+#define I2C_OADDR1_ADDMODE                      ((uint16_t)0x8000) /* Addressing Mode (Slave mode) */
+
+/*******************  Bit definition for I2C_OADDR2 register  *******************/
+#define I2C_OADDR2_ENDUAL                       ((uint8_t)0x01) /* Dual addressing mode enable */
+#define I2C_OADDR2_ADD2                         ((uint8_t)0xFE) /* Interface address */
+
+/********************  Bit definition for I2C_DATAR register  ********************/
+#define I2C_DR_DATAR                            ((uint8_t)0xFF) /* 8-bit Data Register */
+
+/*******************  Bit definition for I2C_STAR1 register  ********************/
+#define I2C_STAR1_SB                            ((uint16_t)0x0001) /* Start Bit (Master mode) */
+#define I2C_STAR1_ADDR                          ((uint16_t)0x0002) /* Address sent (master mode)/matched (slave mode) */
+#define I2C_STAR1_BTF                           ((uint16_t)0x0004) /* Byte Transfer Finished */
+#define I2C_STAR1_ADD10                         ((uint16_t)0x0008) /* 10-bit header sent (Master mode) */
+#define I2C_STAR1_STOPF                         ((uint16_t)0x0010) /* Stop detection (Slave mode) */
+#define I2C_STAR1_RXNE                          ((uint16_t)0x0040) /* Data Register not Empty (receivers) */
+#define I2C_STAR1_TXE                           ((uint16_t)0x0080) /* Data Register Empty (transmitters) */
+#define I2C_STAR1_BERR                          ((uint16_t)0x0100) /* Bus Error */
+#define I2C_STAR1_ARLO                          ((uint16_t)0x0200) /* Arbitration Lost (master mode) */
+#define I2C_STAR1_AF                            ((uint16_t)0x0400) /* Acknowledge Failure */
+#define I2C_STAR1_OVR                           ((uint16_t)0x0800) /* Overrun/Underrun */
+#define I2C_STAR1_PECERR                        ((uint16_t)0x1000) /* PEC Error in reception */
+#define I2C_STAR1_TIMEOUT                       ((uint16_t)0x4000) /* Timeout or Tlow Error */
+#define I2C_STAR1_SMBALERT                      ((uint16_t)0x8000) /* SMBus Alert */
+
+/*******************  Bit definition for I2C_STAR2 register  ********************/
+#define I2C_STAR2_MSL                           ((uint16_t)0x0001) /* Master/Slave */
+#define I2C_STAR2_BUSY                          ((uint16_t)0x0002) /* Bus Busy */
+#define I2C_STAR2_TRA                           ((uint16_t)0x0004) /* Transmitter/Receiver */
+#define I2C_STAR2_GENCALL                       ((uint16_t)0x0010) /* General Call Address (Slave mode) */
+#define I2C_STAR2_SMBDEFAULT                    ((uint16_t)0x0020) /* SMBus Device Default Address (Slave mode) */
+#define I2C_STAR2_SMBHOST                       ((uint16_t)0x0040) /* SMBus Host Header (Slave mode) */
+#define I2C_STAR2_DUALF                         ((uint16_t)0x0080) /* Dual Flag (Slave mode) */
+#define I2C_STAR2_PEC                           ((uint16_t)0xFF00) /* Packet Error Checking Register */
+
+/*******************  Bit definition for I2C_CKCFGR register  ********************/
+#define I2C_CKCFGR_CCR                          ((uint16_t)0x0FFF) /* Clock Control Register in Fast/Standard mode (Master mode) */
+#define I2C_CKCFGR_DUTY                         ((uint16_t)0x4000) /* Fast Mode Duty Cycle */
+#define I2C_CKCFGR_FS                           ((uint16_t)0x8000) /* I2C Master Mode Selection */
+
+/******************************************************************************/
+/*                             Power Control                                  */
+/******************************************************************************/
+
+/********************  Bit definition for PWR_CTLR register  ********************/
+#define PWR_CTLR_LPDS                           ((uint16_t)0x0001) /* Low-Power Deepsleep */
+#define PWR_CTLR_PDDS                           ((uint16_t)0x0002) /* Power Down Deepsleep */
+#define PWR_CTLR_CWUF                           ((uint16_t)0x0004) /* Clear Wakeup Flag */
+#define PWR_CTLR_CSBF                           ((uint16_t)0x0008) /* Clear Standby Flag */
+#define PWR_CTLR_PVDE                           ((uint16_t)0x0010) /* Power Voltage Detector Enable */
+
+#define PWR_CTLR_PLS                            ((uint16_t)0x00E0) /* PLS[2:0] bits (PVD Level Selection) */
+#define PWR_CTLR_PLS_0                          ((uint16_t)0x0020) /* Bit 0 */
+#define PWR_CTLR_PLS_1                          ((uint16_t)0x0040) /* Bit 1 */
+#define PWR_CTLR_PLS_2                          ((uint16_t)0x0080) /* Bit 2 */
+
+#define PWR_CTLR_PLS_2V2                        ((uint16_t)0x0000) /* PVD level 2.2V */
+#define PWR_CTLR_PLS_2V3                        ((uint16_t)0x0020) /* PVD level 2.3V */
+#define PWR_CTLR_PLS_2V4                        ((uint16_t)0x0040) /* PVD level 2.4V */
+#define PWR_CTLR_PLS_2V5                        ((uint16_t)0x0060) /* PVD level 2.5V */
+#define PWR_CTLR_PLS_2V6                        ((uint16_t)0x0080) /* PVD level 2.6V */
+#define PWR_CTLR_PLS_2V7                        ((uint16_t)0x00A0) /* PVD level 2.7V */
+#define PWR_CTLR_PLS_2V8                        ((uint16_t)0x00C0) /* PVD level 2.8V */
+#define PWR_CTLR_PLS_2V9                        ((uint16_t)0x00E0) /* PVD level 2.9V */
+
+#define PWR_CTLR_DBP                            ((uint16_t)0x0100) /* Disable Backup Domain write protection */
+
+/*******************  Bit definition for PWR_CSR register  ********************/
+#define PWR_CSR_WUF                             ((uint16_t)0x0001) /* Wakeup Flag */
+#define PWR_CSR_SBF                             ((uint16_t)0x0002) /* Standby Flag */
+#define PWR_CSR_PVDO                            ((uint16_t)0x0004) /* PVD Output */
+#define PWR_CSR_EWUP                            ((uint16_t)0x0100) /* Enable WKUP pin */
+
+/******************************************************************************/
+/*                         Reset and Clock Control                            */
+/******************************************************************************/
+
+/********************  Bit definition for RCC_CTLR register  ********************/
+#define RCC_HSION                               ((uint32_t)0x00000001) /* Internal High Speed clock enable */
+#define RCC_HSIRDY                              ((uint32_t)0x00000002) /* Internal High Speed clock ready flag */
+#define RCC_HSITRIM                             ((uint32_t)0x000000F8) /* Internal High Speed clock trimming */
+#define RCC_HSICAL                              ((uint32_t)0x0000FF00) /* Internal High Speed clock Calibration */
+#define RCC_HSEON                               ((uint32_t)0x00010000) /* External High Speed clock enable */
+#define RCC_HSERDY                              ((uint32_t)0x00020000) /* External High Speed clock ready flag */
+#define RCC_HSEBYP                              ((uint32_t)0x00040000) /* External High Speed clock Bypass */
+#define RCC_CSSON                               ((uint32_t)0x00080000) /* Clock Security System enable */
+#define RCC_PLLON                               ((uint32_t)0x01000000) /* PLL enable */
+#define RCC_PLLRDY                              ((uint32_t)0x02000000) /* PLL clock ready flag */
+
+/*******************  Bit definition for RCC_CFGR0 register  *******************/
+#define RCC_SW                                  ((uint32_t)0x00000003) /* SW[1:0] bits (System clock Switch) */
+#define RCC_SW_0                                ((uint32_t)0x00000001) /* Bit 0 */
+#define RCC_SW_1                                ((uint32_t)0x00000002) /* Bit 1 */
+
+#define RCC_SW_HSI                              ((uint32_t)0x00000000) /* HSI selected as system clock */
+#define RCC_SW_HSE                              ((uint32_t)0x00000001) /* HSE selected as system clock */
+#define RCC_SW_PLL                              ((uint32_t)0x00000002) /* PLL selected as system clock */
+
+#define RCC_SWS                                 ((uint32_t)0x0000000C) /* SWS[1:0] bits (System Clock Switch Status) */
+#define RCC_SWS_0                               ((uint32_t)0x00000004) /* Bit 0 */
+#define RCC_SWS_1                               ((uint32_t)0x00000008) /* Bit 1 */
+
+#define RCC_SWS_HSI                             ((uint32_t)0x00000000) /* HSI oscillator used as system clock */
+#define RCC_SWS_HSE                             ((uint32_t)0x00000004) /* HSE oscillator used as system clock */
+#define RCC_SWS_PLL                             ((uint32_t)0x00000008) /* PLL used as system clock */
+
+#define RCC_HPRE                                ((uint32_t)0x000000F0) /* HPRE[3:0] bits (AHB prescaler) */
+#define RCC_HPRE_0                              ((uint32_t)0x00000010) /* Bit 0 */
+#define RCC_HPRE_1                              ((uint32_t)0x00000020) /* Bit 1 */
+#define RCC_HPRE_2                              ((uint32_t)0x00000040) /* Bit 2 */
+#define RCC_HPRE_3                              ((uint32_t)0x00000080) /* Bit 3 */
+
+#define RCC_HPRE_DIV1                           ((uint32_t)0x00000000) /* SYSCLK not divided */
+#define RCC_HPRE_DIV2                           ((uint32_t)0x00000010) /* SYSCLK divided by 2 */
+#define RCC_HPRE_DIV3                           ((uint32_t)0x00000020) /* SYSCLK divided by 3 */
+#define RCC_HPRE_DIV4                           ((uint32_t)0x00000030) /* SYSCLK divided by 4 */
+#define RCC_HPRE_DIV5                           ((uint32_t)0x00000040) /* SYSCLK divided by 5 */
+#define RCC_HPRE_DIV6                           ((uint32_t)0x00000050) /* SYSCLK divided by 6 */
+#define RCC_HPRE_DIV7                           ((uint32_t)0x00000060) /* SYSCLK divided by 7 */
+#define RCC_HPRE_DIV8                           ((uint32_t)0x00000070) /* SYSCLK divided by 8 */
+#define RCC_HPRE_DIV16                          ((uint32_t)0x000000B0) /* SYSCLK divided by 16 */
+#define RCC_HPRE_DIV32                          ((uint32_t)0x000000C0) /* SYSCLK divided by 32 */
+#define RCC_HPRE_DIV64                          ((uint32_t)0x000000D0) /* SYSCLK divided by 64 */
+#define RCC_HPRE_DIV128                         ((uint32_t)0x000000E0) /* SYSCLK divided by 128 */
+#define RCC_HPRE_DIV256                         ((uint32_t)0x000000F0) /* SYSCLK divided by 256 */
+
+#define RCC_PPRE1                               ((uint32_t)0x00000700) /* PRE1[2:0] bits (APB1 prescaler) */
+#define RCC_PPRE1_0                             ((uint32_t)0x00000100) /* Bit 0 */
+#define RCC_PPRE1_1                             ((uint32_t)0x00000200) /* Bit 1 */
+#define RCC_PPRE1_2                             ((uint32_t)0x00000400) /* Bit 2 */
+
+#define RCC_PPRE1_DIV1                          ((uint32_t)0x00000000) /* HCLK not divided */
+#define RCC_PPRE1_DIV2                          ((uint32_t)0x00000400) /* HCLK divided by 2 */
+#define RCC_PPRE1_DIV4                          ((uint32_t)0x00000500) /* HCLK divided by 4 */
+#define RCC_PPRE1_DIV8                          ((uint32_t)0x00000600) /* HCLK divided by 8 */
+#define RCC_PPRE1_DIV16                         ((uint32_t)0x00000700) /* HCLK divided by 16 */
+
+#define RCC_PPRE2                               ((uint32_t)0x00003800) /* PRE2[2:0] bits (APB2 prescaler) */
+#define RCC_PPRE2_0                             ((uint32_t)0x00000800) /* Bit 0 */
+#define RCC_PPRE2_1                             ((uint32_t)0x00001000) /* Bit 1 */
+#define RCC_PPRE2_2                             ((uint32_t)0x00002000) /* Bit 2 */
+
+#define RCC_PPRE2_DIV1                          ((uint32_t)0x00000000) /* HCLK not divided */
+#define RCC_PPRE2_DIV2                          ((uint32_t)0x00002000) /* HCLK divided by 2 */
+#define RCC_PPRE2_DIV4                          ((uint32_t)0x00002800) /* HCLK divided by 4 */
+#define RCC_PPRE2_DIV8                          ((uint32_t)0x00003000) /* HCLK divided by 8 */
+#define RCC_PPRE2_DIV16                         ((uint32_t)0x00003800) /* HCLK divided by 16 */
+
+#define RCC_ADCPRE                              ((uint32_t)0x0000C000) /* ADCPRE[1:0] bits (ADC prescaler) */
+#define RCC_ADCPRE_0                            ((uint32_t)0x00004000) /* Bit 0 */
+#define RCC_ADCPRE_1                            ((uint32_t)0x00008000) /* Bit 1 */
+
+#define RCC_ADCPRE_DIV2                         ((uint32_t)0x00000000) /* PCLK2 divided by 2 */
+#define RCC_ADCPRE_DIV4                         ((uint32_t)0x00004000) /* PCLK2 divided by 4 */
+#define RCC_ADCPRE_DIV6                         ((uint32_t)0x00008000) /* PCLK2 divided by 6 */
+#define RCC_ADCPRE_DIV8                         ((uint32_t)0x0000C000) /* PCLK2 divided by 8 */
+
+#define RCC_PLLSRC                              ((uint32_t)0x00010000) /* PLL entry clock source */
+
+#define RCC_PLLXTPRE                            ((uint32_t)0x00020000) /* HSE divider for PLL entry */
+
+#define RCC_PLLMULL                             ((uint32_t)0x003C0000) /* PLLMUL[3:0] bits (PLL multiplication factor) */
+#define RCC_PLLMULL_0                           ((uint32_t)0x00040000) /* Bit 0 */
+#define RCC_PLLMULL_1                           ((uint32_t)0x00080000) /* Bit 1 */
+#define RCC_PLLMULL_2                           ((uint32_t)0x00100000) /* Bit 2 */
+#define RCC_PLLMULL_3                           ((uint32_t)0x00200000) /* Bit 3 */
+
+#define RCC_PLLSRC_HSI_Mul2                     ((uint32_t)0x00000000) /* HSI clock*2 selected as PLL entry clock source */
+#define RCC_PLLSRC_HSE_Mul2                     ((uint32_t)0x00010000) /* HSE clock*2 selected as PLL entry clock source */
+
+#define RCC_PLLXTPRE_HSE                        ((uint32_t)0x00000000) /* HSE clock not divided for PLL entry */
+#define RCC_PLLXTPRE_HSE_Div2                   ((uint32_t)0x00020000) /* HSE clock divided by 2 for PLL entry */
+
+#define RCC_PLLMULL2                            ((uint32_t)0x00000000) /* PLL input clock*2 */
+#define RCC_PLLMULL3                            ((uint32_t)0x00040000) /* PLL input clock*3 */
+#define RCC_PLLMULL4                            ((uint32_t)0x00080000) /* PLL input clock*4 */
+#define RCC_PLLMULL5                            ((uint32_t)0x000C0000) /* PLL input clock*5 */
+#define RCC_PLLMULL6                            ((uint32_t)0x00100000) /* PLL input clock*6 */
+#define RCC_PLLMULL7                            ((uint32_t)0x00140000) /* PLL input clock*7 */
+#define RCC_PLLMULL8                            ((uint32_t)0x00180000) /* PLL input clock*8 */
+#define RCC_PLLMULL9                            ((uint32_t)0x001C0000) /* PLL input clock*9 */
+#define RCC_PLLMULL10                           ((uint32_t)0x00200000) /* PLL input clock10 */
+#define RCC_PLLMULL11                           ((uint32_t)0x00240000) /* PLL input clock*11 */
+#define RCC_PLLMULL12                           ((uint32_t)0x00280000) /* PLL input clock*12 */
+#define RCC_PLLMULL13                           ((uint32_t)0x002C0000) /* PLL input clock*13 */
+#define RCC_PLLMULL14                           ((uint32_t)0x00300000) /* PLL input clock*14 */
+#define RCC_PLLMULL15                           ((uint32_t)0x00340000) /* PLL input clock*15 */
+#define RCC_PLLMULL16                           ((uint32_t)0x00380000) /* PLL input clock*16 */
+#define RCC_USBPRE                              ((uint32_t)0x00400000) /* USB Device prescaler */
+
+#define RCC_CFGR0_MCO                           ((uint32_t)0x07000000) /* MCO[2:0] bits (Microcontroller Clock Output) */
+#define RCC_MCO_0                               ((uint32_t)0x01000000) /* Bit 0 */
+#define RCC_MCO_1                               ((uint32_t)0x02000000) /* Bit 1 */
+#define RCC_MCO_2                               ((uint32_t)0x04000000) /* Bit 2 */
+
+#define RCC_MCO_NOCLOCK                         ((uint32_t)0x00000000) /* No clock */
+#define RCC_CFGR0_MCO_SYSCLK                    ((uint32_t)0x04000000) /* System clock selected as MCO source */
+#define RCC_CFGR0_MCO_HSI                       ((uint32_t)0x05000000) /* HSI clock selected as MCO source */
+#define RCC_CFGR0_MCO_HSE                       ((uint32_t)0x06000000) /* HSE clock selected as MCO source  */
+#define RCC_CFGR0_MCO_PLL                       ((uint32_t)0x07000000) /* PLL clock divided by 2 selected as MCO source */
+
+/*******************  Bit definition for RCC_INTR register  ********************/
+#define RCC_LSIRDYF                             ((uint32_t)0x00000001) /* LSI Ready Interrupt flag */
+#define RCC_LSERDYF                             ((uint32_t)0x00000002) /* LSE Ready Interrupt flag */
+#define RCC_HSIRDYF                             ((uint32_t)0x00000004) /* HSI Ready Interrupt flag */
+#define RCC_HSERDYF                             ((uint32_t)0x00000008) /* HSE Ready Interrupt flag */
+#define RCC_PLLRDYF                             ((uint32_t)0x00000010) /* PLL Ready Interrupt flag */
+#define RCC_CSSF                                ((uint32_t)0x00000080) /* Clock Security System Interrupt flag */
+#define RCC_LSIRDYIE                            ((uint32_t)0x00000100) /* LSI Ready Interrupt Enable */
+#define RCC_LSERDYIE                            ((uint32_t)0x00000200) /* LSE Ready Interrupt Enable */
+#define RCC_HSIRDYIE                            ((uint32_t)0x00000400) /* HSI Ready Interrupt Enable */
+#define RCC_HSERDYIE                            ((uint32_t)0x00000800) /* HSE Ready Interrupt Enable */
+#define RCC_PLLRDYIE                            ((uint32_t)0x00001000) /* PLL Ready Interrupt Enable */
+#define RCC_LSIRDYC                             ((uint32_t)0x00010000) /* LSI Ready Interrupt Clear */
+#define RCC_LSERDYC                             ((uint32_t)0x00020000) /* LSE Ready Interrupt Clear */
+#define RCC_HSIRDYC                             ((uint32_t)0x00040000) /* HSI Ready Interrupt Clear */
+#define RCC_HSERDYC                             ((uint32_t)0x00080000) /* HSE Ready Interrupt Clear */
+#define RCC_PLLRDYC                             ((uint32_t)0x00100000) /* PLL Ready Interrupt Clear */
+#define RCC_CSSC                                ((uint32_t)0x00800000) /* Clock Security System Interrupt Clear */
+
+/*****************  Bit definition for RCC_APB2PRSTR register  *****************/
+#define RCC_AFIORST                             ((uint32_t)0x00000001) /* Alternate Function I/O reset */
+#define RCC_IOPARST                             ((uint32_t)0x00000004) /* I/O port A reset */
+#define RCC_IOPBRST                             ((uint32_t)0x00000008) /* I/O port B reset */
+#define RCC_IOPCRST                             ((uint32_t)0x00000010) /* I/O port C reset */
+#define RCC_IOPDRST                             ((uint32_t)0x00000020) /* I/O port D reset */
+#define RCC_ADC1RST                             ((uint32_t)0x00000200) /* ADC 1 interface reset */
+
+#define RCC_ADC2RST                             ((uint32_t)0x00000400) /* ADC 2 interface reset */
+
+#define RCC_TIM1RST                             ((uint32_t)0x00000800) /* TIM1 Timer reset */
+#define RCC_SPI1RST                             ((uint32_t)0x00001000) /* SPI 1 reset */
+#define RCC_USART1RST                           ((uint32_t)0x00004000) /* USART1 reset */
+
+#define RCC_IOPERST                             ((uint32_t)0x00000040) /* I/O port E reset */
+
+/*****************  Bit definition for RCC_APB1PRSTR register  *****************/
+#define RCC_TIM2RST                             ((uint32_t)0x00000001) /* Timer 2 reset */
+#define RCC_TIM3RST                             ((uint32_t)0x00000002) /* Timer 3 reset */
+#define RCC_WWDGRST                             ((uint32_t)0x00000800) /* Window Watchdog reset */
+#define RCC_USART2RST                           ((uint32_t)0x00020000) /* USART 2 reset */
+#define RCC_I2C1RST                             ((uint32_t)0x00200000) /* I2C 1 reset */
+
+#define RCC_CAN1RST                             ((uint32_t)0x02000000) /* CAN1 reset */
+
+#define RCC_BKPRST                              ((uint32_t)0x08000000) /* Backup interface reset */
+#define RCC_PWRRST                              ((uint32_t)0x10000000) /* Power interface reset */
+
+#define RCC_TIM4RST                             ((uint32_t)0x00000004) /* Timer 4 reset */
+#define RCC_SPI2RST                             ((uint32_t)0x00004000) /* SPI 2 reset */
+#define RCC_USART3RST                           ((uint32_t)0x00040000) /* USART 3 reset */
+#define RCC_I2C2RST                             ((uint32_t)0x00400000) /* I2C 2 reset */
+
+#define RCC_USBRST                              ((uint32_t)0x00800000) /* USB Device reset */
+
+/******************  Bit definition for RCC_AHBPCENR register  ******************/
+#define RCC_DMA1EN                              ((uint16_t)0x0001) /* DMA1 clock enable */
+#define RCC_SRAMEN                              ((uint16_t)0x0004) /* SRAM interface clock enable */
+#define RCC_FLITFEN                             ((uint16_t)0x0010) /* FLITF clock enable */
+#define RCC_CRCEN                               ((uint16_t)0x0040) /* CRC clock enable */
+#define RCC_USBHD                               ((uint16_t)0x1000)
+
+/******************  Bit definition for RCC_APB2PCENR register  *****************/
+#define RCC_AFIOEN                              ((uint32_t)0x00000001) /* Alternate Function I/O clock enable */
+#define RCC_IOPAEN                              ((uint32_t)0x00000004) /* I/O port A clock enable */
+#define RCC_IOPBEN                              ((uint32_t)0x00000008) /* I/O port B clock enable */
+#define RCC_IOPCEN                              ((uint32_t)0x00000010) /* I/O port C clock enable */
+#define RCC_IOPDEN                              ((uint32_t)0x00000020) /* I/O port D clock enable */
+#define RCC_ADC1EN                              ((uint32_t)0x00000200) /* ADC 1 interface clock enable */
+
+#define RCC_ADC2EN                              ((uint32_t)0x00000400) /* ADC 2 interface clock enable */
+
+#define RCC_TIM1EN                              ((uint32_t)0x00000800) /* TIM1 Timer clock enable */
+#define RCC_SPI1EN                              ((uint32_t)0x00001000) /* SPI 1 clock enable */
+#define RCC_USART1EN                            ((uint32_t)0x00004000) /* USART1 clock enable */
+
+/*****************  Bit definition for RCC_APB1PCENR register  ******************/
+#define RCC_TIM2EN                              ((uint32_t)0x00000001) /* Timer 2 clock enabled*/
+#define RCC_TIM3EN                              ((uint32_t)0x00000002) /* Timer 3 clock enable */
+#define RCC_WWDGEN                              ((uint32_t)0x00000800) /* Window Watchdog clock enable */
+#define RCC_USART2EN                            ((uint32_t)0x00020000) /* USART 2 clock enable */
+#define RCC_I2C1EN                              ((uint32_t)0x00200000) /* I2C 1 clock enable */
+
+#define RCC_BKPEN                               ((uint32_t)0x08000000) /* Backup interface clock enable */
+#define RCC_PWREN                               ((uint32_t)0x10000000) /* Power interface clock enable */
+
+#define RCC_USBEN                               ((uint32_t)0x00800000) /* USB Device clock enable */
+
+/*******************  Bit definition for RCC_RSTSCKR register  ********************/
+#define RCC_LSION                               ((uint32_t)0x00000001) /* Internal Low Speed oscillator enable */
+#define RCC_LSIRDY                              ((uint32_t)0x00000002) /* Internal Low Speed oscillator Ready */
+#define RCC_RMVF                                ((uint32_t)0x01000000) /* Remove reset flag */
+#define RCC_PINRSTF                             ((uint32_t)0x04000000) /* PIN reset flag */
+#define RCC_PORRSTF                             ((uint32_t)0x08000000) /* POR/PDR reset flag */
+#define RCC_SFTRSTF                             ((uint32_t)0x10000000) /* Software Reset flag */
+#define RCC_IWDGRSTF                            ((uint32_t)0x20000000) /* Independent Watchdog reset flag */
+#define RCC_WWDGRSTF                            ((uint32_t)0x40000000) /* Window watchdog reset flag */
+#define RCC_LPWRRSTF                            ((uint32_t)0x80000000) /* Low-Power reset flag */
+
+/******************************************************************************/
+/*                        Serial Peripheral Interface                         */
+/******************************************************************************/
+
+/*******************  Bit definition for SPI_CTLR1 register  ********************/
+#define SPI_CTLR1_CPHA                          ((uint16_t)0x0001) /* Clock Phase */
+#define SPI_CTLR1_CPOL                          ((uint16_t)0x0002) /* Clock Polarity */
+#define SPI_CTLR1_MSTR                          ((uint16_t)0x0004) /* Master Selection */
+
+#define SPI_CTLR1_BR                            ((uint16_t)0x0038) /* BR[2:0] bits (Baud Rate Control) */
+#define SPI_CTLR1_BR_0                          ((uint16_t)0x0008) /* Bit 0 */
+#define SPI_CTLR1_BR_1                          ((uint16_t)0x0010) /* Bit 1 */
+#define SPI_CTLR1_BR_2                          ((uint16_t)0x0020) /* Bit 2 */
+
+#define SPI_CTLR1_SPE                           ((uint16_t)0x0040) /* SPI Enable */
+#define SPI_CTLR1_SSI                           ((uint16_t)0x0100) /* Internal slave select */
+#define SPI_CTLR1_SSM                           ((uint16_t)0x0200) /* Software slave management */
+#define SPI_CTLR1_RXONLY                        ((uint16_t)0x0400) /* Receive only */
+#define SPI_CTLR1_DFF                           ((uint16_t)0x0800) /* Data Frame Format */
+#define SPI_CTLR1_CRCNEXT                       ((uint16_t)0x1000) /* Transmit CRC next */
+#define SPI_CTLR1_CRCEN                         ((uint16_t)0x2000) /* Hardware CRC calculation enable */
+#define SPI_CTLR1_BIDIOE                        ((uint16_t)0x4000) /* Output enable in bidirectional mode */
+#define SPI_CTLR1_BIDIMODE                      ((uint16_t)0x8000) /* Bidirectional data mode enable */
+
+/*******************  Bit definition for SPI_CTLR2 register  ********************/
+#define SPI_CTLR2_RXDMAEN                       ((uint8_t)0x01) /* Rx Buffer DMA Enable */
+#define SPI_CTLR2_TXDMAEN                       ((uint8_t)0x02) /* Tx Buffer DMA Enable */
+#define SPI_CTLR2_SSOE                          ((uint8_t)0x04) /* SS Output Enable */
+#define SPI_CTLR2_ERRIE                         ((uint8_t)0x20) /* Error Interrupt Enable */
+#define SPI_CTLR2_RXNEIE                        ((uint8_t)0x40) /* RX buffer Not Empty Interrupt Enable */
+#define SPI_CTLR2_TXEIE                         ((uint8_t)0x80) /* Tx buffer Empty Interrupt Enable */
+
+/********************  Bit definition for SPI_STATR register  ********************/
+#define SPI_STATR_RXNE                          ((uint8_t)0x01) /* Receive buffer Not Empty */
+#define SPI_STATR_TXE                           ((uint8_t)0x02) /* Transmit buffer Empty */
+#define SPI_STATR_CHSIDE                        ((uint8_t)0x04) /* Channel side */
+#define SPI_STATR_UDR                           ((uint8_t)0x08) /* Underrun flag */
+#define SPI_STATR_CRCERR                        ((uint8_t)0x10) /* CRC Error flag */
+#define SPI_STATR_MODF                          ((uint8_t)0x20) /* Mode fault */
+#define SPI_STATR_OVR                           ((uint8_t)0x40) /* Overrun flag */
+#define SPI_STATR_BSY                           ((uint8_t)0x80) /* Busy flag */
+
+/********************  Bit definition for SPI_DATAR register  ********************/
+#define SPI_DATAR_DR                            ((uint16_t)0xFFFF) /* Data Register */
+
+/*******************  Bit definition for SPI_CRCR register  ******************/
+#define SPI_CRCR_CRCPOLY                        ((uint16_t)0xFFFF) /* CRC polynomial register */
+
+/******************  Bit definition for SPI_RCRCR register  ******************/
+#define SPI_RCRCR_RXCRC                         ((uint16_t)0xFFFF) /* Rx CRC Register */
+
+/******************  Bit definition for SPI_TCRCR register  ******************/
+#define SPI_TCRCR_TXCRC                         ((uint16_t)0xFFFF) /* Tx CRC Register */
+
+/******************************************************************************/
+/*                                    TIM                                     */
+/******************************************************************************/
+
+/*******************  Bit definition for TIM_CTLR1 register  ********************/
+#define TIM_CEN                                 ((uint16_t)0x0001) /* Counter enable */
+#define TIM_UDIS                                ((uint16_t)0x0002) /* Update disable */
+#define TIM_URS                                 ((uint16_t)0x0004) /* Update request source */
+#define TIM_OPM                                 ((uint16_t)0x0008) /* One pulse mode */
+#define TIM_DIR                                 ((uint16_t)0x0010) /* Direction */
+
+#define TIM_CMS                                 ((uint16_t)0x0060) /* CMS[1:0] bits (Center-aligned mode selection) */
+#define TIM_CMS_0                               ((uint16_t)0x0020) /* Bit 0 */
+#define TIM_CMS_1                               ((uint16_t)0x0040) /* Bit 1 */
+
+#define TIM_ARPE                                ((uint16_t)0x0080) /* Auto-reload preload enable */
+
+#define TIM_CTLR1_CKD                           ((uint16_t)0x0300) /* CKD[1:0] bits (clock division) */
+#define TIM_CKD_0                               ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_CKD_1                               ((uint16_t)0x0200) /* Bit 1 */
+
+/*******************  Bit definition for TIM_CTLR2 register  ********************/
+#define TIM_CCPC                                ((uint16_t)0x0001) /* Capture/Compare Preloaded Control */
+#define TIM_CCUS                                ((uint16_t)0x0004) /* Capture/Compare Control Update Selection */
+#define TIM_CCDS                                ((uint16_t)0x0008) /* Capture/Compare DMA Selection */
+
+#define TIM_MMS                                 ((uint16_t)0x0070) /* MMS[2:0] bits (Master Mode Selection) */
+#define TIM_MMS_0                               ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_MMS_1                               ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_MMS_2                               ((uint16_t)0x0040) /* Bit 2 */
+
+#define TIM_TI1S                                ((uint16_t)0x0080) /* TI1 Selection */
+#define TIM_OIS1                                ((uint16_t)0x0100) /* Output Idle state 1 (OC1 output) */
+#define TIM_OIS1N                               ((uint16_t)0x0200) /* Output Idle state 1 (OC1N output) */
+#define TIM_OIS2                                ((uint16_t)0x0400) /* Output Idle state 2 (OC2 output) */
+#define TIM_OIS2N                               ((uint16_t)0x0800) /* Output Idle state 2 (OC2N output) */
+#define TIM_OIS3                                ((uint16_t)0x1000) /* Output Idle state 3 (OC3 output) */
+#define TIM_OIS3N                               ((uint16_t)0x2000) /* Output Idle state 3 (OC3N output) */
+#define TIM_OIS4                                ((uint16_t)0x4000) /* Output Idle state 4 (OC4 output) */
+
+/*******************  Bit definition for TIM_SMCFGR register  *******************/
+#define TIM_SMS                                 ((uint16_t)0x0007) /* SMS[2:0] bits (Slave mode selection) */
+#define TIM_SMS_0                               ((uint16_t)0x0001) /* Bit 0 */
+#define TIM_SMS_1                               ((uint16_t)0x0002) /* Bit 1 */
+#define TIM_SMS_2                               ((uint16_t)0x0004) /* Bit 2 */
+
+#define TIM_TS                                  ((uint16_t)0x0070) /* TS[2:0] bits (Trigger selection) */
+#define TIM_TS_0                                ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_TS_1                                ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_TS_2                                ((uint16_t)0x0040) /* Bit 2 */
+
+#define TIM_MSM                                 ((uint16_t)0x0080) /* Master/slave mode */
+
+#define TIM_ETF                                 ((uint16_t)0x0F00) /* ETF[3:0] bits (External trigger filter) */
+#define TIM_ETF_0                               ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_ETF_1                               ((uint16_t)0x0200) /* Bit 1 */
+#define TIM_ETF_2                               ((uint16_t)0x0400) /* Bit 2 */
+#define TIM_ETF_3                               ((uint16_t)0x0800) /* Bit 3 */
+
+#define TIM_ETPS                                ((uint16_t)0x3000) /* ETPS[1:0] bits (External trigger prescaler) */
+#define TIM_ETPS_0                              ((uint16_t)0x1000) /* Bit 0 */
+#define TIM_ETPS_1                              ((uint16_t)0x2000) /* Bit 1 */
+
+#define TIM_ECE                                 ((uint16_t)0x4000) /* External clock enable */
+#define TIM_ETP                                 ((uint16_t)0x8000) /* External trigger polarity */
+
+/*******************  Bit definition for TIM_DMAINTENR register  *******************/
+#define TIM_UIE                                 ((uint16_t)0x0001) /* Update interrupt enable */
+#define TIM_CC1IE                               ((uint16_t)0x0002) /* Capture/Compare 1 interrupt enable */
+#define TIM_CC2IE                               ((uint16_t)0x0004) /* Capture/Compare 2 interrupt enable */
+#define TIM_CC3IE                               ((uint16_t)0x0008) /* Capture/Compare 3 interrupt enable */
+#define TIM_CC4IE                               ((uint16_t)0x0010) /* Capture/Compare 4 interrupt enable */
+#define TIM_COMIE                               ((uint16_t)0x0020) /* COM interrupt enable */
+#define TIM_TIE                                 ((uint16_t)0x0040) /* Trigger interrupt enable */
+#define TIM_BIE                                 ((uint16_t)0x0080) /* Break interrupt enable */
+#define TIM_UDE                                 ((uint16_t)0x0100) /* Update DMA request enable */
+#define TIM_CC1DE                               ((uint16_t)0x0200) /* Capture/Compare 1 DMA request enable */
+#define TIM_CC2DE                               ((uint16_t)0x0400) /* Capture/Compare 2 DMA request enable */
+#define TIM_CC3DE                               ((uint16_t)0x0800) /* Capture/Compare 3 DMA request enable */
+#define TIM_CC4DE                               ((uint16_t)0x1000) /* Capture/Compare 4 DMA request enable */
+#define TIM_COMDE                               ((uint16_t)0x2000) /* COM DMA request enable */
+#define TIM_TDE                                 ((uint16_t)0x4000) /* Trigger DMA request enable */
+
+/********************  Bit definition for TIM_INTFR register  ********************/
+#define TIM_UIF                                 ((uint16_t)0x0001) /* Update interrupt Flag */
+#define TIM_CC1IF                               ((uint16_t)0x0002) /* Capture/Compare 1 interrupt Flag */
+#define TIM_CC2IF                               ((uint16_t)0x0004) /* Capture/Compare 2 interrupt Flag */
+#define TIM_CC3IF                               ((uint16_t)0x0008) /* Capture/Compare 3 interrupt Flag */
+#define TIM_CC4IF                               ((uint16_t)0x0010) /* Capture/Compare 4 interrupt Flag */
+#define TIM_COMIF                               ((uint16_t)0x0020) /* COM interrupt Flag */
+#define TIM_TIF                                 ((uint16_t)0x0040) /* Trigger interrupt Flag */
+#define TIM_BIF                                 ((uint16_t)0x0080) /* Break interrupt Flag */
+#define TIM_CC1OF                               ((uint16_t)0x0200) /* Capture/Compare 1 Overcapture Flag */
+#define TIM_CC2OF                               ((uint16_t)0x0400) /* Capture/Compare 2 Overcapture Flag */
+#define TIM_CC3OF                               ((uint16_t)0x0800) /* Capture/Compare 3 Overcapture Flag */
+#define TIM_CC4OF                               ((uint16_t)0x1000) /* Capture/Compare 4 Overcapture Flag */
+
+/*******************  Bit definition for TIM_SWEVGR register  ********************/
+#define TIM_UG                                  ((uint8_t)0x01) /* Update Generation */
+#define TIM_CC1G                                ((uint8_t)0x02) /* Capture/Compare 1 Generation */
+#define TIM_CC2G                                ((uint8_t)0x04) /* Capture/Compare 2 Generation */
+#define TIM_CC3G                                ((uint8_t)0x08) /* Capture/Compare 3 Generation */
+#define TIM_CC4G                                ((uint8_t)0x10) /* Capture/Compare 4 Generation */
+#define TIM_COMG                                ((uint8_t)0x20) /* Capture/Compare Control Update Generation */
+#define TIM_TG                                  ((uint8_t)0x40) /* Trigger Generation */
+#define TIM_BG                                  ((uint8_t)0x80) /* Break Generation */
+
+/******************  Bit definition for TIM_CHCTLR1 register  *******************/
+#define TIM_CC1S                                ((uint16_t)0x0003) /* CC1S[1:0] bits (Capture/Compare 1 Selection) */
+#define TIM_CC1S_0                              ((uint16_t)0x0001) /* Bit 0 */
+#define TIM_CC1S_1                              ((uint16_t)0x0002) /* Bit 1 */
+
+#define TIM_OC1FE                               ((uint16_t)0x0004) /* Output Compare 1 Fast enable */
+#define TIM_OC1PE                               ((uint16_t)0x0008) /* Output Compare 1 Preload enable */
+
+#define TIM_OC1M                                ((uint16_t)0x0070) /* OC1M[2:0] bits (Output Compare 1 Mode) */
+#define TIM_OC1M_0                              ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_OC1M_1                              ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_OC1M_2                              ((uint16_t)0x0040) /* Bit 2 */
+
+#define TIM_OC1CE                               ((uint16_t)0x0080) /* Output Compare 1Clear Enable */
+
+#define TIM_CC2S                                ((uint16_t)0x0300) /* CC2S[1:0] bits (Capture/Compare 2 Selection) */
+#define TIM_CC2S_0                              ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_CC2S_1                              ((uint16_t)0x0200) /* Bit 1 */
+
+#define TIM_OC2FE                               ((uint16_t)0x0400) /* Output Compare 2 Fast enable */
+#define TIM_OC2PE                               ((uint16_t)0x0800) /* Output Compare 2 Preload enable */
+
+#define TIM_OC2M                                ((uint16_t)0x7000) /* OC2M[2:0] bits (Output Compare 2 Mode) */
+#define TIM_OC2M_0                              ((uint16_t)0x1000) /* Bit 0 */
+#define TIM_OC2M_1                              ((uint16_t)0x2000) /* Bit 1 */
+#define TIM_OC2M_2                              ((uint16_t)0x4000) /* Bit 2 */
+
+#define TIM_OC2CE                               ((uint16_t)0x8000) /* Output Compare 2 Clear Enable */
+
+#define TIM_IC1PSC                              ((uint16_t)0x000C) /* IC1PSC[1:0] bits (Input Capture 1 Prescaler) */
+#define TIM_IC1PSC_0                            ((uint16_t)0x0004) /* Bit 0 */
+#define TIM_IC1PSC_1                            ((uint16_t)0x0008) /* Bit 1 */
+
+#define TIM_IC1F                                ((uint16_t)0x00F0) /* IC1F[3:0] bits (Input Capture 1 Filter) */
+#define TIM_IC1F_0                              ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_IC1F_1                              ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_IC1F_2                              ((uint16_t)0x0040) /* Bit 2 */
+#define TIM_IC1F_3                              ((uint16_t)0x0080) /* Bit 3 */
+
+#define TIM_IC2PSC                              ((uint16_t)0x0C00) /* IC2PSC[1:0] bits (Input Capture 2 Prescaler) */
+#define TIM_IC2PSC_0                            ((uint16_t)0x0400) /* Bit 0 */
+#define TIM_IC2PSC_1                            ((uint16_t)0x0800) /* Bit 1 */
+
+#define TIM_IC2F                                ((uint16_t)0xF000) /* IC2F[3:0] bits (Input Capture 2 Filter) */
+#define TIM_IC2F_0                              ((uint16_t)0x1000) /* Bit 0 */
+#define TIM_IC2F_1                              ((uint16_t)0x2000) /* Bit 1 */
+#define TIM_IC2F_2                              ((uint16_t)0x4000) /* Bit 2 */
+#define TIM_IC2F_3                              ((uint16_t)0x8000) /* Bit 3 */
+
+/******************  Bit definition for TIM_CHCTLR2 register  *******************/
+#define TIM_CC3S                                ((uint16_t)0x0003) /* CC3S[1:0] bits (Capture/Compare 3 Selection) */
+#define TIM_CC3S_0                              ((uint16_t)0x0001) /* Bit 0 */
+#define TIM_CC3S_1                              ((uint16_t)0x0002) /* Bit 1 */
+
+#define TIM_OC3FE                               ((uint16_t)0x0004) /* Output Compare 3 Fast enable */
+#define TIM_OC3PE                               ((uint16_t)0x0008) /* Output Compare 3 Preload enable */
+
+#define TIM_OC3M                                ((uint16_t)0x0070) /* OC3M[2:0] bits (Output Compare 3 Mode) */
+#define TIM_OC3M_0                              ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_OC3M_1                              ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_OC3M_2                              ((uint16_t)0x0040) /* Bit 2 */
+
+#define TIM_OC3CE                               ((uint16_t)0x0080) /* Output Compare 3 Clear Enable */
+
+#define TIM_CC4S                                ((uint16_t)0x0300) /* CC4S[1:0] bits (Capture/Compare 4 Selection) */
+#define TIM_CC4S_0                              ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_CC4S_1                              ((uint16_t)0x0200) /* Bit 1 */
+
+#define TIM_OC4FE                               ((uint16_t)0x0400) /* Output Compare 4 Fast enable */
+#define TIM_OC4PE                               ((uint16_t)0x0800) /* Output Compare 4 Preload enable */
+
+#define TIM_OC4M                                ((uint16_t)0x7000) /* OC4M[2:0] bits (Output Compare 4 Mode) */
+#define TIM_OC4M_0                              ((uint16_t)0x1000) /* Bit 0 */
+#define TIM_OC4M_1                              ((uint16_t)0x2000) /* Bit 1 */
+#define TIM_OC4M_2                              ((uint16_t)0x4000) /* Bit 2 */
+
+#define TIM_OC4CE                               ((uint16_t)0x8000) /* Output Compare 4 Clear Enable */
+
+#define TIM_IC3PSC                              ((uint16_t)0x000C) /* IC3PSC[1:0] bits (Input Capture 3 Prescaler) */
+#define TIM_IC3PSC_0                            ((uint16_t)0x0004) /* Bit 0 */
+#define TIM_IC3PSC_1                            ((uint16_t)0x0008) /* Bit 1 */
+
+#define TIM_IC3F                                ((uint16_t)0x00F0) /* IC3F[3:0] bits (Input Capture 3 Filter) */
+#define TIM_IC3F_0                              ((uint16_t)0x0010) /* Bit 0 */
+#define TIM_IC3F_1                              ((uint16_t)0x0020) /* Bit 1 */
+#define TIM_IC3F_2                              ((uint16_t)0x0040) /* Bit 2 */
+#define TIM_IC3F_3                              ((uint16_t)0x0080) /* Bit 3 */
+
+#define TIM_IC4PSC                              ((uint16_t)0x0C00) /* IC4PSC[1:0] bits (Input Capture 4 Prescaler) */
+#define TIM_IC4PSC_0                            ((uint16_t)0x0400) /* Bit 0 */
+#define TIM_IC4PSC_1                            ((uint16_t)0x0800) /* Bit 1 */
+
+#define TIM_IC4F                                ((uint16_t)0xF000) /* IC4F[3:0] bits (Input Capture 4 Filter) */
+#define TIM_IC4F_0                              ((uint16_t)0x1000) /* Bit 0 */
+#define TIM_IC4F_1                              ((uint16_t)0x2000) /* Bit 1 */
+#define TIM_IC4F_2                              ((uint16_t)0x4000) /* Bit 2 */
+#define TIM_IC4F_3                              ((uint16_t)0x8000) /* Bit 3 */
+
+/*******************  Bit definition for TIM_CCER register  *******************/
+#define TIM_CC1E                                ((uint16_t)0x0001) /* Capture/Compare 1 output enable */
+#define TIM_CC1P                                ((uint16_t)0x0002) /* Capture/Compare 1 output Polarity */
+#define TIM_CC1NE                               ((uint16_t)0x0004) /* Capture/Compare 1 Complementary output enable */
+#define TIM_CC1NP                               ((uint16_t)0x0008) /* Capture/Compare 1 Complementary output Polarity */
+#define TIM_CC2E                                ((uint16_t)0x0010) /* Capture/Compare 2 output enable */
+#define TIM_CC2P                                ((uint16_t)0x0020) /* Capture/Compare 2 output Polarity */
+#define TIM_CC2NE                               ((uint16_t)0x0040) /* Capture/Compare 2 Complementary output enable */
+#define TIM_CC2NP                               ((uint16_t)0x0080) /* Capture/Compare 2 Complementary output Polarity */
+#define TIM_CC3E                                ((uint16_t)0x0100) /* Capture/Compare 3 output enable */
+#define TIM_CC3P                                ((uint16_t)0x0200) /* Capture/Compare 3 output Polarity */
+#define TIM_CC3NE                               ((uint16_t)0x0400) /* Capture/Compare 3 Complementary output enable */
+#define TIM_CC3NP                               ((uint16_t)0x0800) /* Capture/Compare 3 Complementary output Polarity */
+#define TIM_CC4E                                ((uint16_t)0x1000) /* Capture/Compare 4 output enable */
+#define TIM_CC4P                                ((uint16_t)0x2000) /* Capture/Compare 4 output Polarity */
+#define TIM_CC4NP                               ((uint16_t)0x8000) /* Capture/Compare 4 Complementary output Polarity */
+
+/*******************  Bit definition for TIM_CNT register  ********************/
+#define TIM_CNT                                 ((uint16_t)0xFFFF) /* Counter Value */
+
+/*******************  Bit definition for TIM_PSC register  ********************/
+#define TIM_PSC                                 ((uint16_t)0xFFFF) /* Prescaler Value */
+
+/*******************  Bit definition for TIM_ATRLR register  ********************/
+#define TIM_ARR                                 ((uint16_t)0xFFFF) /* actual auto-reload Value */
+
+/*******************  Bit definition for TIM_RPTCR register  ********************/
+#define TIM_REP                                 ((uint8_t)0xFF) /* Repetition Counter Value */
+
+/*******************  Bit definition for TIM_CH1CVR register  *******************/
+#define TIM_CCR1                                ((uint16_t)0xFFFF) /* Capture/Compare 1 Value */
+
+/*******************  Bit definition for TIM_CH2CVR register  *******************/
+#define TIM_CCR2                                ((uint16_t)0xFFFF) /* Capture/Compare 2 Value */
+
+/*******************  Bit definition for TIM_CH3CVR register  *******************/
+#define TIM_CCR3                                ((uint16_t)0xFFFF) /* Capture/Compare 3 Value */
+
+/*******************  Bit definition for TIM_CH4CVR register  *******************/
+#define TIM_CCR4                                ((uint16_t)0xFFFF) /* Capture/Compare 4 Value */
+
+/*******************  Bit definition for TIM_BDTR register  *******************/
+#define TIM_DTG                                 ((uint16_t)0x00FF) /* DTG[0:7] bits (Dead-Time Generator set-up) */
+#define TIM_DTG_0                               ((uint16_t)0x0001) /* Bit 0 */
+#define TIM_DTG_1                               ((uint16_t)0x0002) /* Bit 1 */
+#define TIM_DTG_2                               ((uint16_t)0x0004) /* Bit 2 */
+#define TIM_DTG_3                               ((uint16_t)0x0008) /* Bit 3 */
+#define TIM_DTG_4                               ((uint16_t)0x0010) /* Bit 4 */
+#define TIM_DTG_5                               ((uint16_t)0x0020) /* Bit 5 */
+#define TIM_DTG_6                               ((uint16_t)0x0040) /* Bit 6 */
+#define TIM_DTG_7                               ((uint16_t)0x0080) /* Bit 7 */
+
+#define TIM_LOCK                                ((uint16_t)0x0300) /* LOCK[1:0] bits (Lock Configuration) */
+#define TIM_LOCK_0                              ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_LOCK_1                              ((uint16_t)0x0200) /* Bit 1 */
+
+#define TIM_OSSI                                ((uint16_t)0x0400) /* Off-State Selection for Idle mode */
+#define TIM_OSSR                                ((uint16_t)0x0800) /* Off-State Selection for Run mode */
+#define TIM_BKE                                 ((uint16_t)0x1000) /* Break enable */
+#define TIM_BKP                                 ((uint16_t)0x2000) /* Break Polarity */
+#define TIM_AOE                                 ((uint16_t)0x4000) /* Automatic Output enable */
+#define TIM_MOE                                 ((uint16_t)0x8000) /* Main Output enable */
+
+/*******************  Bit definition for TIM_DMACFGR register  ********************/
+#define TIM_DBA                                 ((uint16_t)0x001F) /* DBA[4:0] bits (DMA Base Address) */
+#define TIM_DBA_0                               ((uint16_t)0x0001) /* Bit 0 */
+#define TIM_DBA_1                               ((uint16_t)0x0002) /* Bit 1 */
+#define TIM_DBA_2                               ((uint16_t)0x0004) /* Bit 2 */
+#define TIM_DBA_3                               ((uint16_t)0x0008) /* Bit 3 */
+#define TIM_DBA_4                               ((uint16_t)0x0010) /* Bit 4 */
+
+#define TIM_DBL                                 ((uint16_t)0x1F00) /* DBL[4:0] bits (DMA Burst Length) */
+#define TIM_DBL_0                               ((uint16_t)0x0100) /* Bit 0 */
+#define TIM_DBL_1                               ((uint16_t)0x0200) /* Bit 1 */
+#define TIM_DBL_2                               ((uint16_t)0x0400) /* Bit 2 */
+#define TIM_DBL_3                               ((uint16_t)0x0800) /* Bit 3 */
+#define TIM_DBL_4                               ((uint16_t)0x1000) /* Bit 4 */
+
+/*******************  Bit definition for TIM_DMAADR register  *******************/
+#define TIM_DMAR_DMAB                           ((uint16_t)0xFFFF) /* DMA register for burst accesses */
+
+/******************************************************************************/
+/*         Universal Synchronous Asynchronous Receiver Transmitter            */
+/******************************************************************************/
+
+/*******************  Bit definition for USART_STATR register  *******************/
+#define USART_STATR_PE                          ((uint16_t)0x0001) /* Parity Error */
+#define USART_STATR_FE                          ((uint16_t)0x0002) /* Framing Error */
+#define USART_STATR_NE                          ((uint16_t)0x0004) /* Noise Error Flag */
+#define USART_STATR_ORE                         ((uint16_t)0x0008) /* OverRun Error */
+#define USART_STATR_IDLE                        ((uint16_t)0x0010) /* IDLE line detected */
+#define USART_STATR_RXNE                        ((uint16_t)0x0020) /* Read Data Register Not Empty */
+#define USART_STATR_TC                          ((uint16_t)0x0040) /* Transmission Complete */
+#define USART_STATR_TXE                         ((uint16_t)0x0080) /* Transmit Data Register Empty */
+#define USART_STATR_LBD                         ((uint16_t)0x0100) /* LIN Break Detection Flag */
+#define USART_STATR_CTS                         ((uint16_t)0x0200) /* CTS Flag */
+
+/*******************  Bit definition for USART_DATAR register  *******************/
+#define USART_DATAR_DR                          ((uint16_t)0x01FF) /* Data value */
+
+/******************  Bit definition for USART_BRR register  *******************/
+#define USART_BRR_DIV_Fraction                  ((uint16_t)0x000F) /* Fraction of USARTDIV */
+#define USART_BRR_DIV_Mantissa                  ((uint16_t)0xFFF0) /* Mantissa of USARTDIV */
+
+/******************  Bit definition for USART_CTLR1 register  *******************/
+#define USART_CTLR1_SBK                         ((uint16_t)0x0001) /* Send Break */
+#define USART_CTLR1_RWU                         ((uint16_t)0x0002) /* Receiver wakeup */
+#define USART_CTLR1_RE                          ((uint16_t)0x0004) /* Receiver Enable */
+#define USART_CTLR1_TE                          ((uint16_t)0x0008) /* Transmitter Enable */
+#define USART_CTLR1_IDLEIE                      ((uint16_t)0x0010) /* IDLE Interrupt Enable */
+#define USART_CTLR1_RXNEIE                      ((uint16_t)0x0020) /* RXNE Interrupt Enable */
+#define USART_CTLR1_TCIE                        ((uint16_t)0x0040) /* Transmission Complete Interrupt Enable */
+#define USART_CTLR1_TXEIE                       ((uint16_t)0x0080) /* PE Interrupt Enable */
+#define USART_CTLR1_PEIE                        ((uint16_t)0x0100) /* PE Interrupt Enable */
+#define USART_CTLR1_PS                          ((uint16_t)0x0200) /* Parity Selection */
+#define USART_CTLR1_PCE                         ((uint16_t)0x0400) /* Parity Control Enable */
+#define USART_CTLR1_WAKE                        ((uint16_t)0x0800) /* Wakeup method */
+#define USART_CTLR1_M                           ((uint16_t)0x1000) /* Word length */
+#define USART_CTLR1_UE                          ((uint16_t)0x2000) /* USART Enable */
+#define USART_CTLR1_OVER8                       ((uint16_t)0x8000) /* USART Oversmapling 8-bits */
+
+/******************  Bit definition for USART_CTLR2 register  *******************/
+#define USART_CTLR2_ADD                         ((uint16_t)0x000F) /* Address of the USART node */
+#define USART_CTLR2_LBDL                        ((uint16_t)0x0020) /* LIN Break Detection Length */
+#define USART_CTLR2_LBDIE                       ((uint16_t)0x0040) /* LIN Break Detection Interrupt Enable */
+#define USART_CTLR2_LBCL                        ((uint16_t)0x0100) /* Last Bit Clock pulse */
+#define USART_CTLR2_CPHA                        ((uint16_t)0x0200) /* Clock Phase */
+#define USART_CTLR2_CPOL                        ((uint16_t)0x0400) /* Clock Polarity */
+#define USART_CTLR2_CLKEN                       ((uint16_t)0x0800) /* Clock Enable */
+
+#define USART_CTLR2_STOP                        ((uint16_t)0x3000) /* STOP[1:0] bits (STOP bits) */
+#define USART_CTLR2_STOP_0                      ((uint16_t)0x1000) /* Bit 0 */
+#define USART_CTLR2_STOP_1                      ((uint16_t)0x2000) /* Bit 1 */
+
+#define USART_CTLR2_LINEN                       ((uint16_t)0x4000) /* LIN mode enable */
+
+/******************  Bit definition for USART_CTLR3 register  *******************/
+#define USART_CTLR3_EIE                         ((uint16_t)0x0001) /* Error Interrupt Enable */
+#define USART_CTLR3_IREN                        ((uint16_t)0x0002) /* IrDA mode Enable */
+#define USART_CTLR3_IRLP                        ((uint16_t)0x0004) /* IrDA Low-Power */
+#define USART_CTLR3_HDSEL                       ((uint16_t)0x0008) /* Half-Duplex Selection */
+#define USART_CTLR3_NACK                        ((uint16_t)0x0010) /* Smartcard NACK enable */
+#define USART_CTLR3_SCEN                        ((uint16_t)0x0020) /* Smartcard mode enable */
+#define USART_CTLR3_DMAR                        ((uint16_t)0x0040) /* DMA Enable Receiver */
+#define USART_CTLR3_DMAT                        ((uint16_t)0x0080) /* DMA Enable Transmitter */
+#define USART_CTLR3_RTSE                        ((uint16_t)0x0100) /* RTS Enable */
+#define USART_CTLR3_CTSE                        ((uint16_t)0x0200) /* CTS Enable */
+#define USART_CTLR3_CTSIE                       ((uint16_t)0x0400) /* CTS Interrupt Enable */
+#define USART_CTLR3_ONEBIT                      ((uint16_t)0x0800) /* One Bit method */
+
+/******************  Bit definition for USART_GPR register  ******************/
+#define USART_GPR_PSC                           ((uint16_t)0x00FF) /* PSC[7:0] bits (Prescaler value) */
+#define USART_GPR_PSC_0                         ((uint16_t)0x0001) /* Bit 0 */
+#define USART_GPR_PSC_1                         ((uint16_t)0x0002) /* Bit 1 */
+#define USART_GPR_PSC_2                         ((uint16_t)0x0004) /* Bit 2 */
+#define USART_GPR_PSC_3                         ((uint16_t)0x0008) /* Bit 3 */
+#define USART_GPR_PSC_4                         ((uint16_t)0x0010) /* Bit 4 */
+#define USART_GPR_PSC_5                         ((uint16_t)0x0020) /* Bit 5 */
+#define USART_GPR_PSC_6                         ((uint16_t)0x0040) /* Bit 6 */
+#define USART_GPR_PSC_7                         ((uint16_t)0x0080) /* Bit 7 */
+
+#define USART_GPR_GT                            ((uint16_t)0xFF00) /* Guard time value */
+
+/******************************************************************************/
+/*                            Window WATCHDOG                                 */
+/******************************************************************************/
+
+/*******************  Bit definition for WWDG_CTLR register  ********************/
+#define WWDG_CTLR_T                             ((uint8_t)0x7F) /* T[6:0] bits (7-Bit counter (MSB to LSB)) */
+#define WWDG_CTLR_T0                            ((uint8_t)0x01) /* Bit 0 */
+#define WWDG_CTLR_T1                            ((uint8_t)0x02) /* Bit 1 */
+#define WWDG_CTLR_T2                            ((uint8_t)0x04) /* Bit 2 */
+#define WWDG_CTLR_T3                            ((uint8_t)0x08) /* Bit 3 */
+#define WWDG_CTLR_T4                            ((uint8_t)0x10) /* Bit 4 */
+#define WWDG_CTLR_T5                            ((uint8_t)0x20) /* Bit 5 */
+#define WWDG_CTLR_T6                            ((uint8_t)0x40) /* Bit 6 */
+
+#define WWDG_CTLR_WDGA                          ((uint8_t)0x80) /* Activation bit */
+
+/*******************  Bit definition for WWDG_CFGR register  *******************/
+#define WWDG_CFGR_W                             ((uint16_t)0x007F) /* W[6:0] bits (7-bit window value) */
+#define WWDG_CFGR_W0                            ((uint16_t)0x0001) /* Bit 0 */
+#define WWDG_CFGR_W1                            ((uint16_t)0x0002) /* Bit 1 */
+#define WWDG_CFGR_W2                            ((uint16_t)0x0004) /* Bit 2 */
+#define WWDG_CFGR_W3                            ((uint16_t)0x0008) /* Bit 3 */
+#define WWDG_CFGR_W4                            ((uint16_t)0x0010) /* Bit 4 */
+#define WWDG_CFGR_W5                            ((uint16_t)0x0020) /* Bit 5 */
+#define WWDG_CFGR_W6                            ((uint16_t)0x0040) /* Bit 6 */
+
+#define WWDG_CFGR_WDGTB                         ((uint16_t)0x0180) /* WDGTB[1:0] bits (Timer Base) */
+#define WWDG_CFGR_WDGTB0                        ((uint16_t)0x0080) /* Bit 0 */
+#define WWDG_CFGR_WDGTB1                        ((uint16_t)0x0100) /* Bit 1 */
+
+#define WWDG_CFGR_EWI                           ((uint16_t)0x0200) /* Early Wakeup Interrupt */
+
+/*******************  Bit definition for WWDG_STATR register  ********************/
+#define WWDG_STATR_EWIF                         ((uint8_t)0x01) /* Early Wakeup Interrupt Flag */
+
+/******************************************************************************/
+/*                          ENHANCED FUNNCTION                                */
+/******************************************************************************/
+
+/****************************  Enhanced register  *****************************/
+#define EXTEN_LOCKUP_EN                         ((uint32_t)0x00000040) /* Bit 6 */
+#define EXTEN_LOCKUP_RSTF                       ((uint32_t)0x00000080) /* Bit 7 */
+
+#define EXTEN_LDO_TRIM                          ((uint32_t)0x00000400) /* Bit 10 */
+
+#define EXTEN_OPA_EN                            ((uint32_t)0x00010000)
+#define EXTEN_OPA_NSEL                          ((uint32_t)0x00020000)
+#define EXTEN_OPA_PSEL                          ((uint32_t)0x00040000)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CH32V00x_H */
+
+
+
+
+
+
+
+/*
+ * This file contains the contents of various parts of the evt.
+ * 
+ * The collection of this file was generated by cnlohr, 2023-02-18
+ *
+ * Contents subject to below copyright where applicable by law. 
+ *
+ * (IANAL, BUT Because it is an interface, it is unlikely protected by copyright)
+ *
+ *********************************** (C) COPYRIGHT *******************************
+ * File Name          : ------------------
+ * Author             : WCH
+ * Version            : V1.0.0
+ * Date               : 2020/08/08
+ * Description        : Library configuration file.
+*********************************************************************************
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* Attention: This software (modified or not) and binary are used for 
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#ifndef __CH32V00x_CONF_H
+#define __CH32V00x_CONF_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* ch32v00x_gpio.c -----------------------------------------------------------*/
+/* MASK */
+#define LSB_MASK                  ((uint16_t)0xFFFF)
+#define DBGAFR_POSITION_MASK      ((uint32_t)0x000F0000)
+#define DBGAFR_SDI_MASK           ((uint32_t)0xF8FFFFFF)
+#define DBGAFR_LOCATION_MASK      ((uint32_t)0x00200000)
+#define DBGAFR_NUMBITS_MASK       ((uint32_t)0x00100000)
+
+
+/* ch32v00x_adc.c ------------------------------------------------------------*/
+/*
+/* ADC DISCNUM mask */
+#define CTLR1_DISCNUM_Reset              ((uint32_t)0xFFFF1FFF)
+
+/* ADC DISCEN mask */
+#define CTLR1_DISCEN_Set                 ((uint32_t)0x00000800)
+#define CTLR1_DISCEN_Reset               ((uint32_t)0xFFFFF7FF)
+
+/* ADC JAUTO mask */
+#define CTLR1_JAUTO_Set                  ((uint32_t)0x00000400)
+#define CTLR1_JAUTO_Reset                ((uint32_t)0xFFFFFBFF)
+
+/* ADC JDISCEN mask */
+#define CTLR1_JDISCEN_Set                ((uint32_t)0x00001000)
+#define CTLR1_JDISCEN_Reset              ((uint32_t)0xFFFFEFFF)
+
+/* ADC AWDCH mask */
+#define CTLR1_AWDCH_Reset                ((uint32_t)0xFFFFFFE0)
+
+/* ADC Analog watchdog enable mode mask */
+#define CTLR1_AWDMode_Reset              ((uint32_t)0xFF3FFDFF)
+
+///* CTLR1 register Mask */
+//Editor's Note: Overloaded Definition
+#define ADC_CTLR1_CLEAR_Mask                 ((uint32_t)0xFFF0FEFF)
+
+/* ADC ADON mask */
+#define CTLR2_ADON_Set                   ((uint32_t)0x00000001)
+#define CTLR2_ADON_Reset                 ((uint32_t)0xFFFFFFFE)
+
+/* ADC DMA mask */
+#define CTLR2_DMA_Set                    ((uint32_t)0x00000100)
+#define CTLR2_DMA_Reset                  ((uint32_t)0xFFFFFEFF)
+
+/* ADC RSTCAL mask */
+#define CTLR2_RSTCAL_Set                 ((uint32_t)0x00000008)
+
+/* ADC CAL mask */
+#define CTLR2_CAL_Set                    ((uint32_t)0x00000004)
+
+/* ADC SWSTART mask */
+#define CTLR2_SWSTART_Set                ((uint32_t)0x00400000)
+
+/* ADC EXTTRIG mask */
+#define CTLR2_EXTTRIG_Set                ((uint32_t)0x00100000)
+#define CTLR2_EXTTRIG_Reset              ((uint32_t)0xFFEFFFFF)
+
+/* ADC Software start mask */
+#define CTLR2_EXTTRIG_SWSTART_Set        ((uint32_t)0x00500000)
+#define CTLR2_EXTTRIG_SWSTART_Reset      ((uint32_t)0xFFAFFFFF)
+
+/* ADC JEXTSEL mask */
+#define CTLR2_JEXTSEL_Reset              ((uint32_t)0xFFFF8FFF)
+
+/* ADC JEXTTRIG mask */
+#define CTLR2_JEXTTRIG_Set               ((uint32_t)0x00008000)
+#define CTLR2_JEXTTRIG_Reset             ((uint32_t)0xFFFF7FFF)
+
+/* ADC JSWSTART mask */
+#define CTLR2_JSWSTART_Set               ((uint32_t)0x00200000)
+
+/* ADC injected software start mask */
+#define CTLR2_JEXTTRIG_JSWSTART_Set      ((uint32_t)0x00208000)
+#define CTLR2_JEXTTRIG_JSWSTART_Reset    ((uint32_t)0xFFDF7FFF)
+
+/* ADC TSPD mask */
+#define CTLR2_TSVREFE_Set                ((uint32_t)0x00800000)
+#define CTLR2_TSVREFE_Reset              ((uint32_t)0xFF7FFFFF)
+
+/* CTLR2 register Mask */
+#define CTLR2_CLEAR_Mask                 ((uint32_t)0xFFF1F7FD)
+
+/* ADC SQx mask */
+#define RSQR3_SQ_Set                     ((uint32_t)0x0000001F)
+#define RSQR2_SQ_Set                     ((uint32_t)0x0000001F)
+#define RSQR1_SQ_Set                     ((uint32_t)0x0000001F)
+
+/* RSQR1 register Mask */
+#define RSQR1_CLEAR_Mask                 ((uint32_t)0xFF0FFFFF)
+
+/* ADC JSQx mask */
+#define ISQR_JSQ_Set                     ((uint32_t)0x0000001F)
+
+/* ADC JL mask */
+#define ISQR_JL_Set                      ((uint32_t)0x00300000)
+#define ISQR_JL_Reset                    ((uint32_t)0xFFCFFFFF)
+
+/* ADC SMPx mask */
+#define SAMPTR1_SMP_Set                  ((uint32_t)0x00000007)
+#define SAMPTR2_SMP_Set                  ((uint32_t)0x00000007)
+
+/* ADC IDATARx registers offset */
+#define IDATAR_Offset                    ((uint8_t)0x28)
+
+
+/* ch32v00x_dbgmcu.c ---------------------------------------------------------*/
+#define IDCODE_DEVID_MASK    ((uint32_t)0x0000FFFF)
+
+
+/* ch32v00x_dma.c ------------------------------------------------------------*/
+
+/* DMA1 Channelx interrupt pending bit masks */
+#define DMA1_Channel1_IT_Mask    ((uint32_t)(DMA_GIF1 | DMA_TCIF1 | DMA_HTIF1 | DMA_TEIF1))
+#define DMA1_Channel2_IT_Mask    ((uint32_t)(DMA_GIF2 | DMA_TCIF2 | DMA_HTIF2 | DMA_TEIF2))
+#define DMA1_Channel3_IT_Mask    ((uint32_t)(DMA_GIF3 | DMA_TCIF3 | DMA_HTIF3 | DMA_TEIF3))
+#define DMA1_Channel4_IT_Mask    ((uint32_t)(DMA_GIF4 | DMA_TCIF4 | DMA_HTIF4 | DMA_TEIF4))
+#define DMA1_Channel5_IT_Mask    ((uint32_t)(DMA_GIF5 | DMA_TCIF5 | DMA_HTIF5 | DMA_TEIF5))
+#define DMA1_Channel6_IT_Mask    ((uint32_t)(DMA_GIF6 | DMA_TCIF6 | DMA_HTIF6 | DMA_TEIF6))
+#define DMA1_Channel7_IT_Mask    ((uint32_t)(DMA_GIF7 | DMA_TCIF7 | DMA_HTIF7 | DMA_TEIF7))
+
+/* DMA2 FLAG mask */
+// Editor's note: Overloaded Definition.
+#define DMA2_FLAG_Mask                ((uint32_t)0x10000000)
+
+/* DMA registers Masks */
+#define CFGR_CLEAR_Mask          ((uint32_t)0xFFFF800F)
+
+/* ch32v00x_exti.c -----------------------------------------------------------*/
+
+
+/* No interrupt selected */
+#define EXTI_LINENONE    ((uint32_t)0x00000)
+
+/* ch32v00x_flash.c ----------------------------------------------------------*/
+
+/* Flash Access Control Register bits */
+#define ACR_LATENCY_Mask           ((uint32_t)0x00000038)
+
+/* Flash Control Register bits */
+#define CR_PG_Set                  ((uint32_t)0x00000001)
+#define CR_PG_Reset                ((uint32_t)0xFFFFFFFE)
+#define CR_PER_Set                 ((uint32_t)0x00000002)
+#define CR_PER_Reset               ((uint32_t)0xFFFFFFFD)
+#define CR_MER_Set                 ((uint32_t)0x00000004)
+#define CR_MER_Reset               ((uint32_t)0xFFFFFFFB)
+#define CR_OPTPG_Set               ((uint32_t)0x00000010)
+#define CR_OPTPG_Reset             ((uint32_t)0xFFFFFFEF)
+#define CR_OPTER_Set               ((uint32_t)0x00000020)
+#define CR_OPTER_Reset             ((uint32_t)0xFFFFFFDF)
+#define CR_STRT_Set                ((uint32_t)0x00000040)
+#define CR_LOCK_Set                ((uint32_t)0x00000080)
+#define CR_PAGE_PG                 ((uint32_t)0x00010000)
+#define CR_PAGE_ER                 ((uint32_t)0x00020000)
+#define CR_BUF_LOAD                ((uint32_t)0x00040000)
+#define CR_BUF_RST                 ((uint32_t)0x00080000)
+
+/* FLASH Status Register bits */
+#define SR_BSY                     ((uint32_t)0x00000001)
+#define SR_WRPRTERR                ((uint32_t)0x00000010)
+#define SR_EOP                     ((uint32_t)0x00000020)
+
+/* FLASH Mask */
+#define RDPRT_Mask                 ((uint32_t)0x00000002)
+#define WRP0_Mask                  ((uint32_t)0x000000FF)
+#define WRP1_Mask                  ((uint32_t)0x0000FF00)
+#define WRP2_Mask                  ((uint32_t)0x00FF0000)
+#define WRP3_Mask                  ((uint32_t)0xFF000000)
+
+/* FLASH Keys */
+#define RDP_Key                    ((uint16_t)0x00A5)
+#define FLASH_KEY1                 ((uint32_t)0x45670123)
+#define FLASH_KEY2                 ((uint32_t)0xCDEF89AB)
+
+/* FLASH BANK address */
+#define FLASH_BANK1_END_ADDRESS    ((uint32_t)0x807FFFF)
+
+/* Delay definition */
+#define EraseTimeout               ((uint32_t)0x000B0000)
+#define ProgramTimeout             ((uint32_t)0x00002000)
+
+/* Flash Program Vaild Address */
+#define ValidAddrStart             (FLASH_BASE)
+#define ValidAddrEnd               (FLASH_BASE + 0x4000)
+
+/* ch32v00x_i2c.c ------------------------------------------------------------*/
+
+
+/* I2C SPE mask */
+#define CTLR1_PE_Set             ((uint16_t)0x0001)
+#define CTLR1_PE_Reset           ((uint16_t)0xFFFE)
+
+/* I2C START mask */
+#define CTLR1_START_Set          ((uint16_t)0x0100)
+#define CTLR1_START_Reset        ((uint16_t)0xFEFF)
+
+/* I2C STOP mask */
+#define CTLR1_STOP_Set           ((uint16_t)0x0200)
+#define CTLR1_STOP_Reset         ((uint16_t)0xFDFF)
+
+/* I2C ACK mask */
+#define CTLR1_ACK_Set            ((uint16_t)0x0400)
+#define CTLR1_ACK_Reset          ((uint16_t)0xFBFF)
+
+/* I2C ENGC mask */
+#define CTLR1_ENGC_Set           ((uint16_t)0x0040)
+#define CTLR1_ENGC_Reset         ((uint16_t)0xFFBF)
+
+/* I2C SWRST mask */
+#define CTLR1_SWRST_Set          ((uint16_t)0x8000)
+#define CTLR1_SWRST_Reset        ((uint16_t)0x7FFF)
+
+/* I2C PEC mask */
+#define CTLR1_PEC_Set            ((uint16_t)0x1000)
+#define CTLR1_PEC_Reset          ((uint16_t)0xEFFF)
+
+/* I2C ENPEC mask */
+#define CTLR1_ENPEC_Set          ((uint16_t)0x0020)
+#define CTLR1_ENPEC_Reset        ((uint16_t)0xFFDF)
+
+/* I2C ENARP mask */
+#define CTLR1_ENARP_Set          ((uint16_t)0x0010)
+#define CTLR1_ENARP_Reset        ((uint16_t)0xFFEF)
+
+/* I2C NOSTRETCH mask */
+#define CTLR1_NOSTRETCH_Set      ((uint16_t)0x0080)
+#define CTLR1_NOSTRETCH_Reset    ((uint16_t)0xFF7F)
+
+////* I2C registers Masks */
+// Editor's note: Overloaded Definition.
+#define I2C_CTLR1_CLEAR_Mask         ((uint16_t)0xFBF5)
+
+/* I2C DMAEN mask */
+#define CTLR2_DMAEN_Set          ((uint16_t)0x0800)
+#define CTLR2_DMAEN_Reset        ((uint16_t)0xF7FF)
+
+/* I2C LAST mask */
+#define CTLR2_LAST_Set           ((uint16_t)0x1000)
+#define CTLR2_LAST_Reset         ((uint16_t)0xEFFF)
+
+/* I2C FREQ mask */
+#define CTLR2_FREQ_Reset         ((uint16_t)0xFFC0)
+
+/* I2C ADD0 mask */
+#define OADDR1_ADD0_Set          ((uint16_t)0x0001)
+#define OADDR1_ADD0_Reset        ((uint16_t)0xFFFE)
+
+/* I2C ENDUAL mask */
+#define OADDR2_ENDUAL_Set        ((uint16_t)0x0001)
+#define OADDR2_ENDUAL_Reset      ((uint16_t)0xFFFE)
+
+/* I2C ADD2 mask */
+#define OADDR2_ADD2_Reset        ((uint16_t)0xFF01)
+
+/* I2C F/S mask */
+#define CKCFGR_FS_Set            ((uint16_t)0x8000)
+
+/* I2C CCR mask */
+#define CKCFGR_CCR_Set           ((uint16_t)0x0FFF)
+
+/* I2C FLAG mask */
+//Editor's Note: Overloaded Definition
+#define I2c_FLAG_Mask                ((uint32_t)0x00FFFFFF)
+
+/* I2C Interrupt Enable mask */
+#define ITEN_Mask                ((uint32_t)0x07000000)
+
+/* ch32v00x_iwdg.c -----------------------------------------------------------*/
+
+/* CTLR register bit mask */
+#define CTLR_KEY_Reload    ((uint16_t)0xAAAA)
+#define CTLR_KEY_Enable    ((uint16_t)0xCCCC)
+
+/* ch32v00x_pwr.c ------------------------------------------------------------*/
+
+
+/* PWR registers bit mask */
+/* CTLR register bit mask */
+#define CTLR_DS_MASK     ((uint32_t)0xFFFFFFFD)
+#define CTLR_PLS_MASK    ((uint32_t)0xFFFFFF1F)
+#define AWUPSC_MASK      ((uint32_t)0xFFFFFFF0)
+#define AWUWR_MASK       ((uint32_t)0xFFFFFFC0)
+
+/* ch32v00x_rcc.c ------------------------------------------------------------*/
+
+/* RCC registers bit address in the alias region */
+#define RCC_OFFSET                 (RCC_BASE - PERIPH_BASE)
+
+/* BDCTLR Register */
+#define BDCTLR_OFFSET              (RCC_OFFSET + 0x20)
+
+/* RCC registers bit mask */
+
+/* CTLR register bit mask */
+#define CTLR_HSEBYP_Reset          ((uint32_t)0xFFFBFFFF)
+#define CTLR_HSEBYP_Set            ((uint32_t)0x00040000)
+#define CTLR_HSEON_Reset           ((uint32_t)0xFFFEFFFF)
+#define CTLR_HSEON_Set             ((uint32_t)0x00010000)
+#define CTLR_HSITRIM_Mask          ((uint32_t)0xFFFFFF07)
+
+#define CFGR0_PLL_Mask             ((uint32_t)0xFFC0FFFF)
+#define CFGR0_PLLMull_Mask         ((uint32_t)0x003C0000)
+#define CFGR0_PLLSRC_Mask          ((uint32_t)0x00010000)
+#define CFGR0_PLLXTPRE_Mask        ((uint32_t)0x00020000)
+#define CFGR0_SWS_Mask             ((uint32_t)0x0000000C)
+#define CFGR0_SW_Mask              ((uint32_t)0xFFFFFFFC)
+#define CFGR0_HPRE_Reset_Mask      ((uint32_t)0xFFFFFF0F)
+#define CFGR0_HPRE_Set_Mask        ((uint32_t)0x000000F0)
+#define CFGR0_PPRE1_Reset_Mask     ((uint32_t)0xFFFFF8FF)
+#define CFGR0_PPRE1_Set_Mask       ((uint32_t)0x00000700)
+#define CFGR0_PPRE2_Reset_Mask     ((uint32_t)0xFFFFC7FF)
+#define CFGR0_PPRE2_Set_Mask       ((uint32_t)0x00003800)
+#define CFGR0_ADCPRE_Reset_Mask    ((uint32_t)0xFFFF07FF)
+#define CFGR0_ADCPRE_Set_Mask      ((uint32_t)0x0000F800)
+
+/* RSTSCKR register bit mask */
+#define RSTSCKR_RMVF_Set           ((uint32_t)0x01000000)
+
+/* RCC Flag Mask */
+//Editor's Note: Overloaded Definition
+#define RCC_FLAG_Mask                  ((uint8_t)0x1F)
+
+/* INTR register byte 2 (Bits[15:8]) base address */
+#define INTR_BYTE2_ADDRESS         ((uint32_t)0x40021009)
+
+/* INTR register byte 3 (Bits[23:16]) base address */
+#define INTR_BYTE3_ADDRESS         ((uint32_t)0x4002100A)
+
+/* CFGR0 register byte 4 (Bits[31:24]) base address */
+#define CFGR0_BYTE4_ADDRESS        ((uint32_t)0x40021007)
+
+/* BDCTLR register base address */
+#define BDCTLR_ADDRESS             (PERIPH_BASE + BDCTLR_OFFSET)
+
+static __I uint8_t APBAHBPrescTable[16] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
+static __I uint8_t ADCPrescTable[20] = {2, 4, 6, 8, 4, 8, 12, 16, 8, 16, 24, 32, 16, 32, 48, 64, 32, 64, 96, 128};
+
+
+/* ch32v00x_spi.c ------------------------------------------------------------*/
+
+
+/* SPI SPE mask */
+#define CTLR1_SPE_Set         ((uint16_t)0x0040)
+#define CTLR1_SPE_Reset       ((uint16_t)0xFFBF)
+
+/* SPI CRCNext mask */
+#define CTLR1_CRCNext_Set     ((uint16_t)0x1000)
+
+/* SPI CRCEN mask */
+#define CTLR1_CRCEN_Set       ((uint16_t)0x2000)
+#define CTLR1_CRCEN_Reset     ((uint16_t)0xDFFF)
+
+/* SPI SSOE mask */
+#define CTLR2_SSOE_Set        ((uint16_t)0x0004)
+#define CTLR2_SSOE_Reset      ((uint16_t)0xFFFB)
+
+/* SPI registers Masks */
+//Editor's Note: Overloaded Definition
+#define SPI_CTLR1_CLEAR_Mask      ((uint16_t)0x3040)
+#define I2SCFGR_CLEAR_Mask    ((uint16_t)0xF040)
+
+
+/* ch32v00x_tim.c ------------------------------------------------------------*/
+
+/* TIM registers bit mask */
+#define SMCFGR_ETR_Mask    ((uint16_t)0x00FF)
+#define CHCTLR_Offset      ((uint16_t)0x0018)
+#define CCER_CCE_Set       ((uint16_t)0x0001)
+#define CCER_CCNE_Set      ((uint16_t)0x0004)
+
+/* ch32v00x_usart.c ----------------------------------------------------------*/
+
+/* USART_Private_Defines */
+#define CTLR1_UE_Set              ((uint16_t)0x2000) /* USART Enable Mask */
+#define CTLR1_UE_Reset            ((uint16_t)0xDFFF) /* USART Disable Mask */
+
+#define CTLR1_WAKE_Mask           ((uint16_t)0xF7FF) /* USART WakeUp Method Mask */
+
+#define CTLR1_RWU_Set             ((uint16_t)0x0002) /* USART mute mode Enable Mask */
+#define CTLR1_RWU_Reset           ((uint16_t)0xFFFD) /* USART mute mode Enable Mask */
+#define CTLR1_SBK_Set             ((uint16_t)0x0001) /* USART Break Character send Mask */
+//Editor's Note: Overloaded Definition
+#define USART_CTLR1_CLEAR_Mask          ((uint16_t)0xE9F3) /* USART CR1 Mask */
+#define CTLR2_Address_Mask        ((uint16_t)0xFFF0) /* USART address Mask */
+
+#define CTLR2_LINEN_Set           ((uint16_t)0x4000) /* USART LIN Enable Mask */
+#define CTLR2_LINEN_Reset         ((uint16_t)0xBFFF) /* USART LIN Disable Mask */
+
+#define CTLR2_LBDL_Mask           ((uint16_t)0xFFDF) /* USART LIN Break detection Mask */
+#define CTLR2_STOP_CLEAR_Mask     ((uint16_t)0xCFFF) /* USART CR2 STOP Bits Mask */
+#define CTLR2_CLOCK_CLEAR_Mask    ((uint16_t)0xF0FF) /* USART CR2 Clock Mask */
+
+#define CTLR3_SCEN_Set            ((uint16_t)0x0020) /* USART SC Enable Mask */
+#define CTLR3_SCEN_Reset          ((uint16_t)0xFFDF) /* USART SC Disable Mask */
+
+#define CTLR3_NACK_Set            ((uint16_t)0x0010) /* USART SC NACK Enable Mask */
+#define CTLR3_NACK_Reset          ((uint16_t)0xFFEF) /* USART SC NACK Disable Mask */
+
+#define CTLR3_HDSEL_Set           ((uint16_t)0x0008) /* USART Half-Duplex Enable Mask */
+#define CTLR3_HDSEL_Reset         ((uint16_t)0xFFF7) /* USART Half-Duplex Disable Mask */
+
+#define CTLR3_IRLP_Mask           ((uint16_t)0xFFFB) /* USART IrDA LowPower mode Mask */
+#define CTLR3_CLEAR_Mask          ((uint16_t)0xFCFF) /* USART CR3 Mask */
+
+#define CTLR3_IREN_Set            ((uint16_t)0x0002) /* USART IrDA Enable Mask */
+#define CTLR3_IREN_Reset          ((uint16_t)0xFFFD) /* USART IrDA Disable Mask */
+#define GPR_LSB_Mask              ((uint16_t)0x00FF) /* Guard Time Register LSB Mask */
+#define GPR_MSB_Mask              ((uint16_t)0xFF00) /* Guard Time Register MSB Mask */
+#define IT_Mask                   ((uint16_t)0x001F) /* USART Interrupt Mask */
+
+/* USART OverSampling-8 Mask */
+#define CTLR1_OVER8_Set           ((uint16_t)0x8000) /* USART OVER8 mode Enable Mask */
+#define CTLR1_OVER8_Reset         ((uint16_t)0x7FFF) /* USART OVER8 mode Disable Mask */
+
+/* USART One Bit Sampling Mask */
+#define CTLR3_ONEBITE_Set         ((uint16_t)0x0800) /* USART ONEBITE mode Enable Mask */
+#define CTLR3_ONEBITE_Reset       ((uint16_t)0xF7FF) /* USART ONEBITE mode Disable Mask */
+
+/* ch32v00x_wwdg.c ------------------------------------------------------------*/
+
+
+/* CTLR register bit mask */
+#define CTLR_WDGA_Set      ((uint32_t)0x00000080)
+
+/* CFGR register bit mask */
+#define CFGR_WDGTB_Mask    ((uint32_t)0xFFFFFE7F)
+#define CFGR_W_Mask        ((uint32_t)0xFFFFFF80)
+#define BIT_Mask           ((uint8_t)0x7F)
+
+
+/* ch32v00x_adc.h ------------------------------------------------------------*/
+
+
+
+/* ADC_mode */
+#define ADC_Mode_Independent                           ((uint32_t)0x00000000)
+
+/* ADC_external_trigger_sources_for_regular_channels_conversion */
+#define ADC_ExternalTrigConv_T1_TRGO                   ((uint32_t)0x00000000)
+#define ADC_ExternalTrigConv_T1_CC1                    ((uint32_t)0x00020000)
+#define ADC_ExternalTrigConv_T1_CC2                    ((uint32_t)0x00040000)
+#define ADC_ExternalTrigConv_T2_TRGO                   ((uint32_t)0x00060000)
+#define ADC_ExternalTrigConv_T2_CC1                    ((uint32_t)0x00080000)
+#define ADC_ExternalTrigConv_T2_CC2                    ((uint32_t)0x000A0000)
+#define ADC_ExternalTrigConv_Ext_PD3_PC2               ((uint32_t)0x000C0000)
+#define ADC_ExternalTrigConv_None                      ((uint32_t)0x000E0000)
+
+/* ADC_data_align */
+#define ADC_DataAlign_Right                            ((uint32_t)0x00000000)
+#define ADC_DataAlign_Left                             ((uint32_t)0x00000800)
+
+/* ADC_channels */
+#define ADC_Channel_0                                  ((uint8_t)0x00)
+#define ADC_Channel_1                                  ((uint8_t)0x01)
+#define ADC_Channel_2                                  ((uint8_t)0x02)
+#define ADC_Channel_3                                  ((uint8_t)0x03)
+#define ADC_Channel_4                                  ((uint8_t)0x04)
+#define ADC_Channel_5                                  ((uint8_t)0x05)
+#define ADC_Channel_6                                  ((uint8_t)0x06)
+#define ADC_Channel_7                                  ((uint8_t)0x07)
+#define ADC_Channel_8                                  ((uint8_t)0x08)
+#define ADC_Channel_9                                  ((uint8_t)0x09)
+
+#define ADC_Channel_Vrefint                            ((uint8_t)ADC_Channel_8)
+#define ADC_Channel_Vcalint                            ((uint8_t)ADC_Channel_9)
+
+/* ADC_sampling_time */
+#define ADC_SampleTime_3Cycles                         ((uint8_t)0x00)
+#define ADC_SampleTime_9Cycles                         ((uint8_t)0x01)
+#define ADC_SampleTime_15Cycles                        ((uint8_t)0x02)
+#define ADC_SampleTime_30Cycles                        ((uint8_t)0x03)
+#define ADC_SampleTime_43Cycles                        ((uint8_t)0x04)
+#define ADC_SampleTime_57Cycles                        ((uint8_t)0x05)
+#define ADC_SampleTime_73Cycles                        ((uint8_t)0x06)
+#define ADC_SampleTime_241Cycles                       ((uint8_t)0x07)
+
+/* ADC_external_trigger_sources_for_injected_channels_conversion */
+#define ADC_ExternalTrigInjecConv_T1_CC3               ((uint32_t)0x00000000)
+#define ADC_ExternalTrigInjecConv_T1_CC4               ((uint32_t)0x00001000)
+#define ADC_ExternalTrigInjecConv_T2_CC3               ((uint32_t)0x00002000)
+#define ADC_ExternalTrigInjecConv_T2_CC4               ((uint32_t)0x00003000)
+#define ADC_ExternalTrigInjecConv_Ext_PD1_PA2          ((uint32_t)0x00006000)
+#define ADC_ExternalTrigInjecConv_None                 ((uint32_t)0x00007000)
+
+/* ADC_injected_channel_selection */
+#define ADC_InjectedChannel_1                          ((uint8_t)0x14)
+#define ADC_InjectedChannel_2                          ((uint8_t)0x18)
+#define ADC_InjectedChannel_3                          ((uint8_t)0x1C)
+#define ADC_InjectedChannel_4                          ((uint8_t)0x20)
+
+/* ADC_analog_watchdog_selection */
+#define ADC_AnalogWatchdog_SingleRegEnable             ((uint32_t)0x00800200)
+#define ADC_AnalogWatchdog_SingleInjecEnable           ((uint32_t)0x00400200)
+#define ADC_AnalogWatchdog_SingleRegOrInjecEnable      ((uint32_t)0x00C00200)
+#define ADC_AnalogWatchdog_AllRegEnable                ((uint32_t)0x00800000)
+#define ADC_AnalogWatchdog_AllInjecEnable              ((uint32_t)0x00400000)
+#define ADC_AnalogWatchdog_AllRegAllInjecEnable        ((uint32_t)0x00C00000)
+#define ADC_AnalogWatchdog_None                        ((uint32_t)0x00000000)
+
+/* ADC_interrupts_definition */
+#define ADC_IT_EOC                                     ((uint16_t)0x0220)
+#define ADC_IT_AWD                                     ((uint16_t)0x0140)
+#define ADC_IT_JEOC                                    ((uint16_t)0x0480)
+
+/* ADC_flags_definition */
+#define ADC_FLAG_AWD                                   ((uint8_t)0x01)
+#define ADC_FLAG_EOC                                   ((uint8_t)0x02)
+#define ADC_FLAG_JEOC                                  ((uint8_t)0x04)
+#define ADC_FLAG_JSTRT                                 ((uint8_t)0x08)
+#define ADC_FLAG_STRT                                  ((uint8_t)0x10)
+
+/* ADC_calibration_voltage_definition */
+#define ADC_CALVOL_50PERCENT                           ((uint32_t)0x02000000)
+#define ADC_CALVOL_75PERCENT                           ((uint32_t)0x04000000)
+
+/* ADC_external_trigger_sources_delay_channels_definition */
+#define ADC_ExternalTrigRegul_DLY                      ((uint32_t)0x00000000)
+#define ADC_ExternalTrigInjec_DLY                      ((uint32_t)0x00020000)
+
+
+
+/* ch32v00x_dbgmcu.h ---------------------------------------------------------*/
+
+/* CFGR0 Register */
+#define DBGMCU_IWDG_STOP             ((uint32_t)0x00000001)
+#define DBGMCU_WWDG_STOP             ((uint32_t)0x00000002)
+#define DBGMCU_TIM1_STOP             ((uint32_t)0x00000010)
+#define DBGMCU_TIM2_STOP             ((uint32_t)0x00000020)
+
+/* ch32v00x_dma.h ------------------------------------------------------------*/
+
+/* DMA_data_transfer_direction */
+#define DMA_DIR_PeripheralDST              ((uint32_t)0x00000010)
+#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000)
+
+/* DMA_peripheral_incremented_mode */
+#define DMA_PeripheralInc_Enable           ((uint32_t)0x00000040)
+#define DMA_PeripheralInc_Disable          ((uint32_t)0x00000000)
+
+/* DMA_memory_incremented_mode */
+#define DMA_MemoryInc_Enable               ((uint32_t)0x00000080)
+#define DMA_MemoryInc_Disable              ((uint32_t)0x00000000)
+
+/* DMA_peripheral_data_size */
+#define DMA_PeripheralDataSize_Byte        ((uint32_t)0x00000000)
+#define DMA_PeripheralDataSize_HalfWord    ((uint32_t)0x00000100)
+#define DMA_PeripheralDataSize_Word        ((uint32_t)0x00000200)
+
+/* DMA_memory_data_size */
+#define DMA_MemoryDataSize_Byte            ((uint32_t)0x00000000)
+#define DMA_MemoryDataSize_HalfWord        ((uint32_t)0x00000400)
+#define DMA_MemoryDataSize_Word            ((uint32_t)0x00000800)
+
+/* DMA_circular_normal_mode */
+#define DMA_Mode_Circular                  ((uint32_t)0x00000020)
+#define DMA_Mode_Normal                    ((uint32_t)0x00000000)
+
+/* DMA_priority_level */
+#define DMA_Priority_VeryHigh              ((uint32_t)0x00003000)
+#define DMA_Priority_High                  ((uint32_t)0x00002000)
+#define DMA_Priority_Medium                ((uint32_t)0x00001000)
+#define DMA_Priority_Low                   ((uint32_t)0x00000000)
+
+/* DMA_memory_to_memory */
+#define DMA_M2M_Enable                     ((uint32_t)0x00004000)
+#define DMA_M2M_Disable                    ((uint32_t)0x00000000)
+
+/* DMA_interrupts_definition */
+#define DMA_IT_TC                          ((uint32_t)0x00000002)
+#define DMA_IT_HT                          ((uint32_t)0x00000004)
+#define DMA_IT_TE                          ((uint32_t)0x00000008)
+
+#define DMA1_IT_GL1                        ((uint32_t)0x00000001)
+#define DMA1_IT_TC1                        ((uint32_t)0x00000002)
+#define DMA1_IT_HT1                        ((uint32_t)0x00000004)
+#define DMA1_IT_TE1                        ((uint32_t)0x00000008)
+#define DMA1_IT_GL2                        ((uint32_t)0x00000010)
+#define DMA1_IT_TC2                        ((uint32_t)0x00000020)
+#define DMA1_IT_HT2                        ((uint32_t)0x00000040)
+#define DMA1_IT_TE2                        ((uint32_t)0x00000080)
+#define DMA1_IT_GL3                        ((uint32_t)0x00000100)
+#define DMA1_IT_TC3                        ((uint32_t)0x00000200)
+#define DMA1_IT_HT3                        ((uint32_t)0x00000400)
+#define DMA1_IT_TE3                        ((uint32_t)0x00000800)
+#define DMA1_IT_GL4                        ((uint32_t)0x00001000)
+#define DMA1_IT_TC4                        ((uint32_t)0x00002000)
+#define DMA1_IT_HT4                        ((uint32_t)0x00004000)
+#define DMA1_IT_TE4                        ((uint32_t)0x00008000)
+#define DMA1_IT_GL5                        ((uint32_t)0x00010000)
+#define DMA1_IT_TC5                        ((uint32_t)0x00020000)
+#define DMA1_IT_HT5                        ((uint32_t)0x00040000)
+#define DMA1_IT_TE5                        ((uint32_t)0x00080000)
+#define DMA1_IT_GL6                        ((uint32_t)0x00100000)
+#define DMA1_IT_TC6                        ((uint32_t)0x00200000)
+#define DMA1_IT_HT6                        ((uint32_t)0x00400000)
+#define DMA1_IT_TE6                        ((uint32_t)0x00800000)
+#define DMA1_IT_GL7                        ((uint32_t)0x01000000)
+#define DMA1_IT_TC7                        ((uint32_t)0x02000000)
+#define DMA1_IT_HT7                        ((uint32_t)0x04000000)
+#define DMA1_IT_TE7                        ((uint32_t)0x08000000)
+
+/* DMA_flags_definition */
+#define DMA1_FLAG_GL1                      ((uint32_t)0x00000001)
+#define DMA1_FLAG_TC1                      ((uint32_t)0x00000002)
+#define DMA1_FLAG_HT1                      ((uint32_t)0x00000004)
+#define DMA1_FLAG_TE1                      ((uint32_t)0x00000008)
+#define DMA1_FLAG_GL2                      ((uint32_t)0x00000010)
+#define DMA1_FLAG_TC2                      ((uint32_t)0x00000020)
+#define DMA1_FLAG_HT2                      ((uint32_t)0x00000040)
+#define DMA1_FLAG_TE2                      ((uint32_t)0x00000080)
+#define DMA1_FLAG_GL3                      ((uint32_t)0x00000100)
+#define DMA1_FLAG_TC3                      ((uint32_t)0x00000200)
+#define DMA1_FLAG_HT3                      ((uint32_t)0x00000400)
+#define DMA1_FLAG_TE3                      ((uint32_t)0x00000800)
+#define DMA1_FLAG_GL4                      ((uint32_t)0x00001000)
+#define DMA1_FLAG_TC4                      ((uint32_t)0x00002000)
+#define DMA1_FLAG_HT4                      ((uint32_t)0x00004000)
+#define DMA1_FLAG_TE4                      ((uint32_t)0x00008000)
+#define DMA1_FLAG_GL5                      ((uint32_t)0x00010000)
+#define DMA1_FLAG_TC5                      ((uint32_t)0x00020000)
+#define DMA1_FLAG_HT5                      ((uint32_t)0x00040000)
+#define DMA1_FLAG_TE5                      ((uint32_t)0x00080000)
+#define DMA1_FLAG_GL6                      ((uint32_t)0x00100000)
+#define DMA1_FLAG_TC6                      ((uint32_t)0x00200000)
+#define DMA1_FLAG_HT6                      ((uint32_t)0x00400000)
+#define DMA1_FLAG_TE6                      ((uint32_t)0x00800000)
+#define DMA1_FLAG_GL7                      ((uint32_t)0x01000000)
+#define DMA1_FLAG_TC7                      ((uint32_t)0x02000000)
+#define DMA1_FLAG_HT7                      ((uint32_t)0x04000000)
+#define DMA1_FLAG_TE7                      ((uint32_t)0x08000000)
+
+/* ch32v00x_exti.h -----------------------------------------------------------*/
+
+/* EXTI mode enumeration */
+typedef enum
+{
+    EXTI_Mode_Interrupt = 0x00,
+    EXTI_Mode_Event = 0x04
+} EXTIMode_TypeDef;
+
+/* EXTI Trigger enumeration */
+typedef enum
+{
+    EXTI_Trigger_Rising = 0x08,
+    EXTI_Trigger_Falling = 0x0C,
+    EXTI_Trigger_Rising_Falling = 0x10
+} EXTITrigger_TypeDef;
+
+/* EXTI_Lines */
+#define EXTI_Line0     ((uint32_t)0x00001) /* External interrupt line 0 */
+#define EXTI_Line1     ((uint32_t)0x00002) /* External interrupt line 1 */
+#define EXTI_Line2     ((uint32_t)0x00004) /* External interrupt line 2 */
+#define EXTI_Line3     ((uint32_t)0x00008) /* External interrupt line 3 */
+#define EXTI_Line4     ((uint32_t)0x00010) /* External interrupt line 4 */
+#define EXTI_Line5     ((uint32_t)0x00020) /* External interrupt line 5 */
+#define EXTI_Line6     ((uint32_t)0x00040) /* External interrupt line 6 */
+#define EXTI_Line7     ((uint32_t)0x00080) /* External interrupt line 7 */
+#define EXTI_Line8     ((uint32_t)0x00100) /* External interrupt line 8 Connected to the PVD Output */
+#define EXTI_Line9     ((uint32_t)0x00200) /* External interrupt line 9 Connected to the PWR Auto Wake-up event*/
+
+
+/* ch32v00x_flash.h ----------------------------------------------------------*/
+
+
+/* FLASH Status */
+typedef enum
+{
+    FLASH_BUSY = 1,
+    FLASH_ERROR_PG,
+    FLASH_ERROR_WRP,
+    FLASH_COMPLETE,
+    FLASH_TIMEOUT
+} FLASH_Status;
+
+
+/* Flash_Latency */
+#define FLASH_Latency_0                  ((uint32_t)0x00000000) /* FLASH Zero Latency cycle */
+#define FLASH_Latency_1                  ((uint32_t)0x00000001) /* FLASH One Latency cycle */
+#define FLASH_Latency_2                  ((uint32_t)0x00000002) /* FLASH Two Latency cycles */
+
+/* Values to be used with CH32V00x devices (1page = 64Byte) */
+#define FLASH_WRProt_Pages0to15          ((uint32_t)0x00000001) /* CH32 Low and Medium density devices: Write protection of page 0 to 15 */
+#define FLASH_WRProt_Pages16to31         ((uint32_t)0x00000002) /* CH32 Low and Medium density devices: Write protection of page 16 to 31 */
+#define FLASH_WRProt_Pages32to47         ((uint32_t)0x00000004) /* CH32 Low and Medium density devices: Write protection of page 32 to 47 */
+#define FLASH_WRProt_Pages48to63         ((uint32_t)0x00000008) /* CH32 Low and Medium density devices: Write protection of page 48 to 63 */
+#define FLASH_WRProt_Pages64to79         ((uint32_t)0x00000010) /* CH32 Low and Medium density devices: Write protection of page 64 to 79 */
+#define FLASH_WRProt_Pages80to95         ((uint32_t)0x00000020) /* CH32 Low and Medium density devices: Write protection of page 80 to 95 */
+#define FLASH_WRProt_Pages96to111        ((uint32_t)0x00000040) /* CH32 Low and Medium density devices: Write protection of page 96 to 111 */
+#define FLASH_WRProt_Pages112to127       ((uint32_t)0x00000080) /* CH32 Low and Medium density devices: Write protection of page 112 to 127 */
+#define FLASH_WRProt_Pages128to143       ((uint32_t)0x00000100) /* CH32 Medium-density devices: Write protection of page 128 to 143 */
+#define FLASH_WRProt_Pages144to159       ((uint32_t)0x00000200) /* CH32 Medium-density devices: Write protection of page 144 to 159 */
+#define FLASH_WRProt_Pages160to175       ((uint32_t)0x00000400) /* CH32 Medium-density devices: Write protection of page 160 to 175 */
+#define FLASH_WRProt_Pages176to191       ((uint32_t)0x00000800) /* CH32 Medium-density devices: Write protection of page 176 to 191 */
+#define FLASH_WRProt_Pages192to207       ((uint32_t)0x00001000) /* CH32 Medium-density devices: Write protection of page 192 to 207 */
+#define FLASH_WRProt_Pages208to223       ((uint32_t)0x00002000) /* CH32 Medium-density devices: Write protection of page 208 to 223 */
+#define FLASH_WRProt_Pages224to239       ((uint32_t)0x00004000) /* CH32 Medium-density devices: Write protection of page 224 to 239 */
+#define FLASH_WRProt_Pages240to255       ((uint32_t)0x00008000) /* CH32 Medium-density devices: Write protection of page 240 to 255 */
+
+#define FLASH_WRProt_AllPages            ((uint32_t)0x0000FFFF) /* Write protection of all Pages */
+
+/* Option_Bytes_IWatchdog */
+#define OB_IWDG_SW                       ((uint16_t)0x0001) /* Software IWDG selected */
+#define OB_IWDG_HW                       ((uint16_t)0x0000) /* Hardware IWDG selected */
+
+/* Option_Bytes_nRST_STOP */
+#define OB_STOP_NoRST                    ((uint16_t)0x0002) /* No reset generated when entering in STOP */
+#define OB_STOP_RST                      ((uint16_t)0x0000) /* Reset generated when entering in STOP */
+
+/* Option_Bytes_nRST_STDBY */
+#define OB_STDBY_NoRST                   ((uint16_t)0x0004) /* No reset generated when entering in STANDBY */
+#define OB_STDBY_RST                     ((uint16_t)0x0000) /* Reset generated when entering in STANDBY */
+
+/* Option_Bytes_RST_ENandDT */
+#define OB_RST_NoEN                      ((uint16_t)0x0018) /* Reset IO disable (PD7)*/
+#define OB_RST_EN_DT12ms                 ((uint16_t)0x0010) /* Reset IO enable (PD7) and  Ignore delay time 12ms */
+#define OB_RST_EN_DT1ms                  ((uint16_t)0x0008) /* Reset IO enable (PD7) and  Ignore delay time 1ms */
+#define OB_RST_EN_DT128ms                ((uint16_t)0x0000) /* Reset IO enable (PD7) and  Ignore delay time 128ms */
+
+/* FLASH_Interrupts */
+#define FLASH_IT_ERROR                   ((uint32_t)0x00000400) /* FPEC error interrupt source */
+#define FLASH_IT_EOP                     ((uint32_t)0x00001000) /* End of FLASH Operation Interrupt source */
+#define FLASH_IT_BANK1_ERROR             FLASH_IT_ERROR         /* FPEC BANK1 error interrupt source */
+#define FLASH_IT_BANK1_EOP               FLASH_IT_EOP           /* End of FLASH BANK1 Operation Interrupt source */
+
+/* FLASH_Flags */
+#define FLASH_FLAG_BSY                   ((uint32_t)0x00000001) /* FLASH Busy flag */
+#define FLASH_FLAG_EOP                   ((uint32_t)0x00000020) /* FLASH End of Operation flag */
+#define FLASH_FLAG_WRPRTERR              ((uint32_t)0x00000010) /* FLASH Write protected error flag */
+#define FLASH_FLAG_OPTERR                ((uint32_t)0x00000001) /* FLASH Option Byte error flag */
+
+#define FLASH_FLAG_BANK1_BSY             FLASH_FLAG_BSY       /* FLASH BANK1 Busy flag*/
+#define FLASH_FLAG_BANK1_EOP             FLASH_FLAG_EOP       /* FLASH BANK1 End of Operation flag */
+#define FLASH_FLAG_BANK1_WRPRTERR        FLASH_FLAG_WRPRTERR  /* FLASH BANK1 Write protected error flag */
+
+/* System_Reset_Start_Mode */
+#define Start_Mode_USER                  ((uint32_t)0x00000000)
+#define Start_Mode_BOOT                  ((uint32_t)0x00004000)
+
+
+/* ch32v00x_gpio.h ------------------------------------------------------------*/
+
+/* Output Maximum frequency selection */
+typedef enum
+{
+    GPIO_Speed_10MHz = 1,
+    GPIO_Speed_2MHz,
+    GPIO_Speed_50MHz
+} GPIOSpeed_TypeDef;
+
+#define GPIO_SPEED_IN 0
+
+#define GPIO_CNF_IN_ANALOG   0
+#define GPIO_CNF_IN_FLOATING 4
+#define GPIO_CNF_IN_PUPD     8
+#define GPIO_CNF_OUT_PP      0
+#define GPIO_CNF_OUT_OD      4
+#define GPIO_CNF_OUT_PP_AF   8
+#define GPIO_CNF_OUT_OD_AF   12
+
+/* Configuration Mode enumeration */
+/*
+typedef enum
+{
+    GPIO_Mode_AIN = 0x0,
+    GPIO_Mode_IN_FLOATING = 0x04,
+    GPIO_Mode_IPD = 0x28,
+    GPIO_Mode_IPU = 0x48,
+    GPIO_Mode_Out_OD = 0x14,
+    GPIO_Mode_Out_PP = 0x10,
+    GPIO_Mode_AF_OD = 0x1C,
+    GPIO_Mode_AF_PP = 0x18
+} GPIOMode_TypeDef;
+*/
+
+
+/* Bit_SET and Bit_RESET enumeration */
+typedef enum
+{
+    Bit_RESET = 0,
+    Bit_SET
+} BitAction;
+
+/* GPIO_pins_define */
+#define GPIO_Pin_0                     ((uint16_t)0x0001) /* Pin 0 selected */
+#define GPIO_Pin_1                     ((uint16_t)0x0002) /* Pin 1 selected */
+#define GPIO_Pin_2                     ((uint16_t)0x0004) /* Pin 2 selected */
+#define GPIO_Pin_3                     ((uint16_t)0x0008) /* Pin 3 selected */
+#define GPIO_Pin_4                     ((uint16_t)0x0010) /* Pin 4 selected */
+#define GPIO_Pin_5                     ((uint16_t)0x0020) /* Pin 5 selected */
+#define GPIO_Pin_6                     ((uint16_t)0x0040) /* Pin 6 selected */
+#define GPIO_Pin_7                     ((uint16_t)0x0080) /* Pin 7 selected */
+#define GPIO_Pin_All                   ((uint16_t)0xFFFF) /* All pins selected */
+
+/* GPIO_Remap_define */
+#define GPIO_Remap_SPI1                ((uint32_t)0x00000001) /* SPI1 Alternate Function mapping */
+#define GPIO_PartialRemap_I2C1         ((uint32_t)0x10000002) /* I2C1 Partial Alternate Function mapping */
+#define GPIO_FullRemap_I2C1            ((uint32_t)0x10400002) /* I2C1 Full Alternate Function mapping */
+#define GPIO_PartialRemap1_USART1      ((uint32_t)0x80000004) /* USART1 Partial1 Alternate Function mapping */
+#define GPIO_PartialRemap2_USART1      ((uint32_t)0x80200000) /* USART1 Partial2 Alternate Function mapping */
+#define GPIO_FullRemap_USART1          ((uint32_t)0x80200004) /* USART1 Full Alternate Function mapping */
+#define GPIO_PartialRemap1_TIM1        ((uint32_t)0x00160040) /* TIM1 Partial1 Alternate Function mapping */
+#define GPIO_PartialRemap2_TIM1        ((uint32_t)0x00160080) /* TIM1 Partial2 Alternate Function mapping */
+#define GPIO_FullRemap_TIM1            ((uint32_t)0x001600C0) /* TIM1 Full Alternate Function mapping */
+#define GPIO_PartialRemap1_TIM2        ((uint32_t)0x00180100) /* TIM2 Partial1 Alternate Function mapping */
+#define GPIO_PartialRemap2_TIM2        ((uint32_t)0x00180200) /* TIM2 Partial2 Alternate Function mapping */
+#define GPIO_FullRemap_TIM2            ((uint32_t)0x00180300) /* TIM2 Full Alternate Function mapping */
+#define GPIO_Remap_PA1_2               ((uint32_t)0x00008000) /* PA1 and PA2 Alternate Function mapping */
+#define GPIO_Remap_ADC1_ETRGINJ        ((uint32_t)0x00200002) /* ADC1 External Trigger Injected Conversion remapping */
+#define GPIO_Remap_ADC1_ETRGREG        ((uint32_t)0x00200004) /* ADC1 External Trigger Regular Conversion remapping */
+#define GPIO_Remap_LSI_CAL             ((uint32_t)0x00200080) /* LSI calibration Alternate Function mapping */
+#define GPIO_Remap_SDI_Disable         ((uint32_t)0x00300400) /* SDI Disabled */
+
+/* GPIO_Port_Sources */
+#define GPIO_PortSourceGPIOA           ((uint8_t)0x00)
+#define GPIO_PortSourceGPIOC           ((uint8_t)0x02)
+#define GPIO_PortSourceGPIOD           ((uint8_t)0x03)
+
+/* GPIO_Pin_sources */
+#define GPIO_PinSource0                ((uint8_t)0x00)
+#define GPIO_PinSource1                ((uint8_t)0x01)
+#define GPIO_PinSource2                ((uint8_t)0x02)
+#define GPIO_PinSource3                ((uint8_t)0x03)
+#define GPIO_PinSource4                ((uint8_t)0x04)
+#define GPIO_PinSource5                ((uint8_t)0x05)
+#define GPIO_PinSource6                ((uint8_t)0x06)
+#define GPIO_PinSource7                ((uint8_t)0x07)
+
+/* ch32v00x_i2c.h ------------------------------------------------------------*/
+
+/* I2C_mode */
+#define I2C_Mode_I2C                                         ((uint16_t)0x0000)
+
+/* I2C_duty_cycle_in_fast_mode */
+#define I2C_DutyCycle_16_9                                   ((uint16_t)0x4000) /* I2C fast mode Tlow/Thigh = 16/9 */
+#define I2C_DutyCycle_2                                      ((uint16_t)0xBFFF) /* I2C fast mode Tlow/Thigh = 2 */
+
+/* I2C_acknowledgement */
+#define I2C_Ack_Enable                                       ((uint16_t)0x0400)
+#define I2C_Ack_Disable                                      ((uint16_t)0x0000)
+
+/* I2C_transfer_direction */
+#define I2C_Direction_Transmitter                            ((uint8_t)0x00)
+#define I2C_Direction_Receiver                               ((uint8_t)0x01)
+
+/* I2C_acknowledged_address */
+#define I2C_AcknowledgedAddress_7bit                         ((uint16_t)0x4000)
+#define I2C_AcknowledgedAddress_10bit                        ((uint16_t)0xC000)
+
+/* I2C_registers */
+#define I2C_Register_CTLR1                                   ((uint8_t)0x00)
+#define I2C_Register_CTLR2                                   ((uint8_t)0x04)
+#define I2C_Register_OADDR1                                  ((uint8_t)0x08)
+#define I2C_Register_OADDR2                                  ((uint8_t)0x0C)
+#define I2C_Register_DATAR                                   ((uint8_t)0x10)
+#define I2C_Register_STAR1                                   ((uint8_t)0x14)
+#define I2C_Register_STAR2                                   ((uint8_t)0x18)
+#define I2C_Register_CKCFGR                                  ((uint8_t)0x1C)
+
+/* I2C_PEC_position */
+#define I2C_PECPosition_Next                                 ((uint16_t)0x0800)
+#define I2C_PECPosition_Current                              ((uint16_t)0xF7FF)
+
+/* I2C_NACK_position */
+#define I2C_NACKPosition_Next                                ((uint16_t)0x0800)
+#define I2C_NACKPosition_Current                             ((uint16_t)0xF7FF)
+
+/* I2C_interrupts_definition */
+#define I2C_IT_BUF                                           ((uint16_t)0x0400)
+#define I2C_IT_EVT                                           ((uint16_t)0x0200)
+#define I2C_IT_ERR                                           ((uint16_t)0x0100)
+
+/* I2C_interrupts_definition */
+#define I2C_IT_PECERR                                        ((uint32_t)0x01001000)
+#define I2C_IT_OVR                                           ((uint32_t)0x01000800)
+#define I2C_IT_AF                                            ((uint32_t)0x01000400)
+#define I2C_IT_ARLO                                          ((uint32_t)0x01000200)
+#define I2C_IT_BERR                                          ((uint32_t)0x01000100)
+#define I2C_IT_TXE                                           ((uint32_t)0x06000080)
+#define I2C_IT_RXNE                                          ((uint32_t)0x06000040)
+#define I2C_IT_STOPF                                         ((uint32_t)0x02000010)
+#define I2C_IT_ADD10                                         ((uint32_t)0x02000008)
+#define I2C_IT_BTF                                           ((uint32_t)0x02000004)
+#define I2C_IT_ADDR                                          ((uint32_t)0x02000002)
+#define I2C_IT_SB                                            ((uint32_t)0x02000001)
+
+/* SR2 register flags  */
+#define I2C_FLAG_DUALF                                       ((uint32_t)0x00800000)
+#define I2C_FLAG_GENCALL                                     ((uint32_t)0x00100000)
+#define I2C_FLAG_TRA                                         ((uint32_t)0x00040000)
+#define I2C_FLAG_BUSY                                        ((uint32_t)0x00020000)
+#define I2C_FLAG_MSL                                         ((uint32_t)0x00010000)
+
+/* SR1 register flags */
+#define I2C_FLAG_PECERR                                      ((uint32_t)0x10001000)
+#define I2C_FLAG_OVR                                         ((uint32_t)0x10000800)
+#define I2C_FLAG_AF                                          ((uint32_t)0x10000400)
+#define I2C_FLAG_ARLO                                        ((uint32_t)0x10000200)
+#define I2C_FLAG_BERR                                        ((uint32_t)0x10000100)
+#define I2C_FLAG_TXE                                         ((uint32_t)0x10000080)
+#define I2C_FLAG_RXNE                                        ((uint32_t)0x10000040)
+#define I2C_FLAG_STOPF                                       ((uint32_t)0x10000010)
+#define I2C_FLAG_ADD10                                       ((uint32_t)0x10000008)
+#define I2C_FLAG_BTF                                         ((uint32_t)0x10000004)
+#define I2C_FLAG_ADDR                                        ((uint32_t)0x10000002)
+#define I2C_FLAG_SB                                          ((uint32_t)0x10000001)
+
+/****************I2C Master Events (Events grouped in order of communication)********************/
+
+/******************************************************************************************************************** 
+  * @brief  Start communicate
+  * 
+  * After master use I2C_GenerateSTART() function sending the START condition,the master 
+  * has to wait for event 5(the Start condition has been correctly 
+  * released on the I2C bus ).
+  * 
+  */
+/* EVT5 */
+#define  I2C_EVENT_MASTER_MODE_SELECT                      ((uint32_t)0x00030001)  /* BUSY, MSL and SB flag */
+
+/********************************************************************************************************************
+  * @brief  Address Acknowledge
+  * 
+  * When start condition correctly released on the bus(check EVT5), the 
+  * master use I2C_Send7bitAddress() function sends the address of the slave(s) with which it will communicate 
+  * it also determines master as transmitter or Receiver. Then the master has to wait that a slave acknowledges 
+  * his address. If an acknowledge is sent on the bus, one of the following events will be set:
+  * 
+  *
+  * 
+  *  1) In case of Master Receiver (7-bit addressing): the I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED 
+  *     event is set.
+  *  
+  *  2) In case of Master Transmitter (7-bit addressing): the I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED 
+  *     is set
+  *  
+  *  3) In case of 10-Bit addressing mode, the master (after generating the START 
+  *  and checking on EVT5) use I2C_SendData() function send the header of 10-bit addressing mode.  
+  *  Then master wait EVT9. EVT9 means that the 10-bit addressing header has been correctly sent 
+  *  on the bus. Then master should use the function I2C_Send7bitAddress() to send the second part 
+  *  of the 10-bit address (LSB) . Then master should wait for event 6. 
+  *
+  *     
+  */
+
+/* EVT6 */
+#define  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED        ((uint32_t)0x00070082)  /* BUSY, MSL, ADDR, TXE and TRA flags */
+#define  I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED           ((uint32_t)0x00030002)  /* BUSY, MSL and ADDR flags */
+/*EVT9 */
+#define  I2C_EVENT_MASTER_MODE_ADDRESS10                   ((uint32_t)0x00030008)  /* BUSY, MSL and ADD10 flags */
+
+/******************************************************************************************************************** 
+  * @brief Communication events
+  * 
+  * If START condition has generated and slave address 
+  * been acknowledged. then the master has to check one of the following events for 
+  * communication procedures:
+  *  
+  * 1) Master Receiver mode: The master has to wait on the event EVT7 then use  
+  *   I2C_ReceiveData() function to read the data received from the slave .
+  * 
+  * 2) Master Transmitter mode: The master use I2C_SendData() function to send data  
+  *     then to wait on event EVT8 or EVT8_2.
+  *    These two events are similar: 
+  *     - EVT8 means that the data has been written in the data register and is 
+  *       being shifted out.
+  *     - EVT8_2 means that the data has been physically shifted out and output 
+  *       on the bus.
+  *     In most cases, using EVT8 is sufficient for the application.
+  *     Using EVT8_2  will leads to a slower communication  speed but will more reliable .
+  *     EVT8_2 is also more suitable than EVT8 for testing on the last data transmission 
+  *    
+  *     
+  *  Note:
+  *  In case the  user software does not guarantee that this event EVT7 is managed before 
+  *  the current byte end of transfer, then user may check on I2C_EVENT_MASTER_BYTE_RECEIVED 
+  *  and I2C_FLAG_BTF flag at the same time .But in this case the communication may be slower.
+  *
+  * 
+  */
+
+/* Master Receive mode */ 
+/* EVT7 */
+#define  I2C_EVENT_MASTER_BYTE_RECEIVED                    ((uint32_t)0x00030040)  /* BUSY, MSL and RXNE flags */
+
+/* Master Transmitter mode*/
+/* EVT8 */
+#define I2C_EVENT_MASTER_BYTE_TRANSMITTING                 ((uint32_t)0x00070080) /* TRA, BUSY, MSL, TXE flags */
+/* EVT8_2 */
+#define  I2C_EVENT_MASTER_BYTE_TRANSMITTED                 ((uint32_t)0x00070084)  /* TRA, BUSY, MSL, TXE and BTF flags */
+
+/******************I2C Slave Events (Events grouped in order of communication)******************/
+
+/******************************************************************************************************************** 
+  * @brief  Start Communicate events
+  * 
+  * Wait on one of these events at the start of the communication. It means that 
+  * the I2C peripheral detected a start condition of master device generate on the bus.  
+  * If the acknowledge feature is enabled through function I2C_AcknowledgeConfig()),The peripheral generates an ACK condition on the bus. 
+  *    
+  *
+  *
+  * a) In normal case (only one address managed by the slave), when the address 
+  *   sent by the master matches the own address of the peripheral (configured by 
+  *   I2C_OwnAddress1 field) the I2C_EVENT_SLAVE_XXX_ADDRESS_MATCHED event is set 
+  *   (where XXX could be TRANSMITTER or RECEIVER).
+  *    
+  * b) In case the address sent by the master matches the second address of the 
+  *   peripheral (configured by the function I2C_OwnAddress2Config() and enabled 
+  *   by the function I2C_DualAddressCmd()) the events I2C_EVENT_SLAVE_XXX_SECONDADDRESS_MATCHED 
+  *   (where XXX could be TRANSMITTER or RECEIVER) are set.
+  *   
+  * c) In case the address sent by the master is General Call (address 0x00) and 
+  *   if the General Call is enabled for the peripheral (using function I2C_GeneralCallCmd()) 
+  *   the following event is set I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED.   
+  * 
+  */
+
+/* EVT1 */   
+/* a) Case of One Single Address managed by the slave */
+#define  I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED          ((uint32_t)0x00020002) /* BUSY and ADDR flags */
+#define  I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED       ((uint32_t)0x00060082) /* TRA, BUSY, TXE and ADDR flags */
+
+/* b) Case of Dual address managed by the slave */
+#define  I2C_EVENT_SLAVE_RECEIVER_SECONDADDRESS_MATCHED    ((uint32_t)0x00820000)  /* DUALF and BUSY flags */
+#define  I2C_EVENT_SLAVE_TRANSMITTER_SECONDADDRESS_MATCHED ((uint32_t)0x00860080)  /* DUALF, TRA, BUSY and TXE flags */
+
+/* c) Case of General Call enabled for the slave */
+#define  I2C_EVENT_SLAVE_GENERALCALLADDRESS_MATCHED        ((uint32_t)0x00120000)  /* GENCALL and BUSY flags */
+
+/******************************************************************************************************************** 
+  * @brief  Communication events
+  * 
+  * Wait on one of these events when EVT1 has already been checked : 
+  * 
+  * - Slave Receiver mode:
+  *     - EVT2--The device is expecting to receive a data byte . 
+  *     - EVT4--The device is expecting the end of the communication: master 
+  *       sends a stop condition and data transmission is stopped.
+  *    
+  * - Slave Transmitter mode:
+  *    - EVT3--When a byte has been transmitted by the slave and the Master is expecting 
+  *      the end of the byte transmission. The two events I2C_EVENT_SLAVE_BYTE_TRANSMITTED and
+  *      I2C_EVENT_SLAVE_BYTE_TRANSMITTING are similar. If the user software doesn't guarantee 
+  *      the EVT3 is managed before the current byte end of transfer The second one can optionally
+  *      be used. 
+  *    - EVT3_2--When the master sends a NACK  to tell slave device that data transmission 
+  *      shall end . The slave device has to stop sending 
+  *      data bytes and wait a Stop condition from bus.
+  *      
+  *  Note:
+  *  If the  user software does not guarantee that the event 2 is 
+  *  managed before the current byte end of transfer, User may check on I2C_EVENT_SLAVE_BYTE_RECEIVED 
+  *  and I2C_FLAG_BTF flag at the same time .
+  *  In this case the communication will be slower.
+  *
+  */
+
+/* Slave Receiver mode*/ 
+/* EVT2 */
+#define  I2C_EVENT_SLAVE_BYTE_RECEIVED                     ((uint32_t)0x00020040)  /* BUSY and RXNE flags */
+/* EVT4  */
+#define  I2C_EVENT_SLAVE_STOP_DETECTED                     ((uint32_t)0x00000010)  /* STOPF flag */
+
+/* Slave Transmitter mode -----------------------*/
+/* EVT3 */
+#define  I2C_EVENT_SLAVE_BYTE_TRANSMITTED                  ((uint32_t)0x00060084)  /* TRA, BUSY, TXE and BTF flags */
+#define  I2C_EVENT_SLAVE_BYTE_TRANSMITTING                 ((uint32_t)0x00060080)  /* TRA, BUSY and TXE flags */
+/*EVT3_2 */
+#define  I2C_EVENT_SLAVE_ACK_FAILURE                       ((uint32_t)0x00000400)  /* AF flag */
+
+
+/* ch32v00x_iwdg.h -----------------------------------------------------------*/
+
+/* IWDG_WriteAccess */
+#define IWDG_WriteAccess_Enable     ((uint16_t)0x5555)
+#define IWDG_WriteAccess_Disable    ((uint16_t)0x0000)
+
+/* IWDG_prescaler */
+#define IWDG_Prescaler_4            ((uint8_t)0x00)
+#define IWDG_Prescaler_8            ((uint8_t)0x01)
+#define IWDG_Prescaler_16           ((uint8_t)0x02)
+#define IWDG_Prescaler_32           ((uint8_t)0x03)
+#define IWDG_Prescaler_64           ((uint8_t)0x04)
+#define IWDG_Prescaler_128          ((uint8_t)0x05)
+#define IWDG_Prescaler_256          ((uint8_t)0x06)
+
+/* IWDG_Flag */
+#define IWDG_FLAG_PVU               ((uint16_t)0x0001)
+#define IWDG_FLAG_RVU               ((uint16_t)0x0002)
+
+
+/* ch32v00x_misc.h -----------------------------------------------------------*/
+
+/* Preemption_Priority_Group */
+#define NVIC_PriorityGroup_0           ((uint32_t)0x00)
+#define NVIC_PriorityGroup_1           ((uint32_t)0x01)
+#define NVIC_PriorityGroup_2           ((uint32_t)0x02)
+#define NVIC_PriorityGroup_3           ((uint32_t)0x03)
+#define NVIC_PriorityGroup_4           ((uint32_t)0x04)
+
+
+/* ch32v00x_opa.h ------------------------------------------------------------*/
+
+/* Editor's note: I don't know if this is actually useful */
+
+/* OPA PSEL enumeration */
+typedef enum
+{
+    CHP0 = 0,
+    CHP1
+} OPA_PSEL_TypeDef;
+
+/* OPA NSEL enumeration */
+typedef enum
+{
+    CHN0 = 0,
+    CHN1
+} OPA_NSEL_TypeDef;
+
+
+/* OPA Init Structure definition */
+typedef struct
+{
+    OPA_PSEL_TypeDef PSEL;    /* Specifies the positive channel of OPA */
+    OPA_NSEL_TypeDef NSEL;    /* Specifies the negative channel of OPA */
+} OPA_InitTypeDef;
+
+
+/* ch32v00x_pwr.h ------------------------------------------------------------*/
+
+
+/* PVD_detection_level  */
+#define PWR_PVDLevel_2V9          ((uint32_t)0x00000000)
+#define PWR_PVDLevel_3V1          ((uint32_t)0x00000020)
+#define PWR_PVDLevel_3V3          ((uint32_t)0x00000040)
+#define PWR_PVDLevel_3V5          ((uint32_t)0x00000060)
+#define PWR_PVDLevel_3V7          ((uint32_t)0x00000080)
+#define PWR_PVDLevel_3V9          ((uint32_t)0x000000A0)
+#define PWR_PVDLevel_4V1          ((uint32_t)0x000000C0)
+#define PWR_PVDLevel_4V4          ((uint32_t)0x000000E0)
+
+/* PWR_AWU_Prescaler */
+#define PWR_AWU_Prescaler_1       ((uint32_t)0x00000000)
+#define PWR_AWU_Prescaler_2       ((uint32_t)0x00000002)
+#define PWR_AWU_Prescaler_4       ((uint32_t)0x00000003)
+#define PWR_AWU_Prescaler_8       ((uint32_t)0x00000004)
+#define PWR_AWU_Prescaler_16      ((uint32_t)0x00000005)
+#define PWR_AWU_Prescaler_32      ((uint32_t)0x00000006)
+#define PWR_AWU_Prescaler_64      ((uint32_t)0x00000007)
+#define PWR_AWU_Prescaler_128     ((uint32_t)0x00000008)
+#define PWR_AWU_Prescaler_256     ((uint32_t)0x00000009)
+#define PWR_AWU_Prescaler_512     ((uint32_t)0x0000000A)
+#define PWR_AWU_Prescaler_1024    ((uint32_t)0x0000000B)
+#define PWR_AWU_Prescaler_2048    ((uint32_t)0x0000000C)
+#define PWR_AWU_Prescaler_4096    ((uint32_t)0x0000000D)
+#define PWR_AWU_Prescaler_10240   ((uint32_t)0x0000000E)
+#define PWR_AWU_Prescaler_61440   ((uint32_t)0x0000000F)
+
+/* STOP_mode_entry */
+#define PWR_STANDBYEntry_WFI      ((uint8_t)0x01)
+#define PWR_STANDBYEntry_WFE      ((uint8_t)0x02)
+
+/* PWR_Flag */
+#define PWR_FLAG_PVDO             ((uint32_t)0x00000004)
+
+
+/* ch32v00x_rcc.h ------------------------------------------------------------*/
+
+
+/* HSE_configuration */
+#define RCC_HSE_OFF                      ((uint32_t)0x00000000)
+#define RCC_HSE_ON                       ((uint32_t)0x00010000)
+#define RCC_HSE_Bypass                   ((uint32_t)0x00040000)
+
+/* PLL_entry_clock_source */
+#define RCC_PLLSource_HSI_MUL2           ((uint32_t)0x00000000)
+#define RCC_PLLSource_HSE_MUL2           ((uint32_t)0x00030000)
+
+/* System_clock_source */
+#define RCC_SYSCLKSource_HSI             ((uint32_t)0x00000000)
+#define RCC_SYSCLKSource_HSE             ((uint32_t)0x00000001)
+#define RCC_SYSCLKSource_PLLCLK          ((uint32_t)0x00000002)
+
+/* AHB_clock_source */
+#define RCC_SYSCLK_Div1                  ((uint32_t)0x00000000)
+#define RCC_SYSCLK_Div2                  ((uint32_t)0x00000010)
+#define RCC_SYSCLK_Div3                  ((uint32_t)0x00000020)
+#define RCC_SYSCLK_Div4                  ((uint32_t)0x00000030)
+#define RCC_SYSCLK_Div5                  ((uint32_t)0x00000040)
+#define RCC_SYSCLK_Div6                  ((uint32_t)0x00000050)
+#define RCC_SYSCLK_Div7                  ((uint32_t)0x00000060)
+#define RCC_SYSCLK_Div8                  ((uint32_t)0x00000070)
+#define RCC_SYSCLK_Div16                 ((uint32_t)0x000000B0)
+#define RCC_SYSCLK_Div32                 ((uint32_t)0x000000C0)
+#define RCC_SYSCLK_Div64                 ((uint32_t)0x000000D0)
+#define RCC_SYSCLK_Div128                ((uint32_t)0x000000E0)
+#define RCC_SYSCLK_Div256                ((uint32_t)0x000000F0)
+
+/* RCC_Interrupt_source */
+#define RCC_IT_LSIRDY                    ((uint8_t)0x01)
+#define RCC_IT_HSIRDY                    ((uint8_t)0x04)
+#define RCC_IT_HSERDY                    ((uint8_t)0x08)
+#define RCC_IT_PLLRDY                    ((uint8_t)0x10)
+#define RCC_IT_CSS                       ((uint8_t)0x80)
+
+/* ADC_clock_source */
+#define RCC_PCLK2_Div2                   ((uint32_t)0x00000000)
+#define RCC_PCLK2_Div4                   ((uint32_t)0x00004000)
+#define RCC_PCLK2_Div6                   ((uint32_t)0x00008000)
+#define RCC_PCLK2_Div8                   ((uint32_t)0x0000C000)
+#define RCC_PCLK2_Div12                  ((uint32_t)0x0000A000)
+#define RCC_PCLK2_Div16                  ((uint32_t)0x0000E000)
+#define RCC_PCLK2_Div24                  ((uint32_t)0x0000A800)
+#define RCC_PCLK2_Div32                  ((uint32_t)0x0000E800)
+#define RCC_PCLK2_Div48                  ((uint32_t)0x0000B000)
+#define RCC_PCLK2_Div64                  ((uint32_t)0x0000F000)
+#define RCC_PCLK2_Div96                  ((uint32_t)0x0000B800)
+#define RCC_PCLK2_Div128                 ((uint32_t)0x0000F800)
+
+/* AHB_peripheral */
+#define RCC_AHBPeriph_DMA1               ((uint32_t)0x00000001)
+#define RCC_AHBPeriph_SRAM               ((uint32_t)0x00000004)
+
+/* APB2_peripheral */
+#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)
+#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)
+#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)
+#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)
+#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)
+#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)
+#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)
+#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)
+
+/* APB1_peripheral */
+#define RCC_APB1Periph_TIM2              ((uint32_t)0x00000001)
+#define RCC_APB1Periph_WWDG              ((uint32_t)0x00000800)
+#define RCC_APB1Periph_I2C1              ((uint32_t)0x00200000)
+#define RCC_APB1Periph_PWR               ((uint32_t)0x10000000)
+
+/* Clock_source_to_output_on_MCO_pin */
+#define RCC_MCO_NoClock                  ((uint8_t)0x00)
+#define RCC_MCO_SYSCLK                   ((uint8_t)0x04)
+#define RCC_MCO_HSI                      ((uint8_t)0x05)
+#define RCC_MCO_HSE                      ((uint8_t)0x06)
+#define RCC_MCO_PLLCLK                   ((uint8_t)0x07)
+
+/* RCC_Flag */
+#define RCC_FLAG_HSIRDY                  ((uint8_t)0x21)
+#define RCC_FLAG_HSERDY                  ((uint8_t)0x31)
+#define RCC_FLAG_PLLRDY                  ((uint8_t)0x39)
+#define RCC_FLAG_LSIRDY                  ((uint8_t)0x61)
+#define RCC_FLAG_PINRST                  ((uint8_t)0x7A)
+#define RCC_FLAG_PORRST                  ((uint8_t)0x7B)
+#define RCC_FLAG_SFTRST                  ((uint8_t)0x7C)
+#define RCC_FLAG_IWDGRST                 ((uint8_t)0x7D)
+#define RCC_FLAG_WWDGRST                 ((uint8_t)0x7E)
+#define RCC_FLAG_LPWRRST                 ((uint8_t)0x7F)
+
+/* SysTick_clock_source */
+#define SysTick_CLKSource_HCLK_Div8      ((uint32_t)0xFFFFFFFB)
+#define SysTick_CLKSource_HCLK           ((uint32_t)0x00000004)
+
+
+/* ch32v00x_spi.h ------------------------------------------------------------*/
+
+
+/* SPI_data_direction */
+#define SPI_Direction_2Lines_FullDuplex    ((uint16_t)0x0000)
+#define SPI_Direction_2Lines_RxOnly        ((uint16_t)0x0400)
+#define SPI_Direction_1Line_Rx             ((uint16_t)0x8000)
+#define SPI_Direction_1Line_Tx             ((uint16_t)0xC000)
+
+/* SPI_mode */
+#define SPI_Mode_Master                    ((uint16_t)0x0104)
+#define SPI_Mode_Slave                     ((uint16_t)0x0000)
+
+/* SPI_data_size */
+#define SPI_DataSize_16b                   ((uint16_t)0x0800)
+#define SPI_DataSize_8b                    ((uint16_t)0x0000)
+
+/* SPI_Clock_Polarity */
+#define SPI_CPOL_Low                       ((uint16_t)0x0000)
+#define SPI_CPOL_High                      ((uint16_t)0x0002)
+
+/* SPI_Clock_Phase */
+#define SPI_CPHA_1Edge                     ((uint16_t)0x0000)
+#define SPI_CPHA_2Edge                     ((uint16_t)0x0001)
+
+/* SPI_Slave_Select_management */
+#define SPI_NSS_Soft                       ((uint16_t)0x0200)
+#define SPI_NSS_Hard                       ((uint16_t)0x0000)
+
+/* SPI_BaudRate_Prescaler */
+#define SPI_BaudRatePrescaler_2            ((uint16_t)0x0000)
+#define SPI_BaudRatePrescaler_4            ((uint16_t)0x0008)
+#define SPI_BaudRatePrescaler_8            ((uint16_t)0x0010)
+#define SPI_BaudRatePrescaler_16           ((uint16_t)0x0018)
+#define SPI_BaudRatePrescaler_32           ((uint16_t)0x0020)
+#define SPI_BaudRatePrescaler_64           ((uint16_t)0x0028)
+#define SPI_BaudRatePrescaler_128          ((uint16_t)0x0030)
+#define SPI_BaudRatePrescaler_256          ((uint16_t)0x0038)
+
+/* SPI_MSB transmission */
+#define SPI_FirstBit_MSB                   ((uint16_t)0x0000)
+
+/* SPI_I2S_DMA_transfer_requests */
+#define SPI_I2S_DMAReq_Tx                  ((uint16_t)0x0002)
+#define SPI_I2S_DMAReq_Rx                  ((uint16_t)0x0001)
+
+/* SPI_NSS_internal_software_management */
+#define SPI_NSSInternalSoft_Set            ((uint16_t)0x0100)
+#define SPI_NSSInternalSoft_Reset          ((uint16_t)0xFEFF)
+
+/* SPI_CRC_Transmit_Receive */
+#define SPI_CRC_Tx                         ((uint8_t)0x00)
+#define SPI_CRC_Rx                         ((uint8_t)0x01)
+
+/* SPI_direction_transmit_receive */
+#define SPI_Direction_Rx                   ((uint16_t)0xBFFF)
+#define SPI_Direction_Tx                   ((uint16_t)0x4000)
+
+/* SPI_I2S_interrupts_definition */
+#define SPI_I2S_IT_TXE                     ((uint8_t)0x71)
+#define SPI_I2S_IT_RXNE                    ((uint8_t)0x60)
+#define SPI_I2S_IT_ERR                     ((uint8_t)0x50)
+#define SPI_I2S_IT_OVR                     ((uint8_t)0x56)
+#define SPI_IT_MODF                        ((uint8_t)0x55)
+#define SPI_IT_CRCERR                      ((uint8_t)0x54)
+#define I2S_IT_UDR                         ((uint8_t)0x53)
+
+/* SPI_I2S_flags_definition */
+#define SPI_I2S_FLAG_RXNE                  ((uint16_t)0x0001)
+#define SPI_I2S_FLAG_TXE                   ((uint16_t)0x0002)
+#define I2S_FLAG_CHSIDE                    ((uint16_t)0x0004)
+#define I2S_FLAG_UDR                       ((uint16_t)0x0008)
+#define SPI_FLAG_CRCERR                    ((uint16_t)0x0010)
+#define SPI_FLAG_MODF                      ((uint16_t)0x0020)
+#define SPI_I2S_FLAG_OVR                   ((uint16_t)0x0040)
+#define SPI_I2S_FLAG_BSY                   ((uint16_t)0x0080)
+
+
+/* ch32v00x_tim.h ------------------------------------------------------------*/
+
+/* TIM_Output_Compare_and_PWM_modes */
+#define TIM_OCMode_Timing                  ((uint16_t)0x0000)
+#define TIM_OCMode_Active                  ((uint16_t)0x0010)
+#define TIM_OCMode_Inactive                ((uint16_t)0x0020)
+#define TIM_OCMode_Toggle                  ((uint16_t)0x0030)
+#define TIM_OCMode_PWM1                    ((uint16_t)0x0060)
+#define TIM_OCMode_PWM2                    ((uint16_t)0x0070)
+
+/* TIM_One_Pulse_Mode */
+#define TIM_OPMode_Single                  ((uint16_t)0x0008)
+#define TIM_OPMode_Repetitive              ((uint16_t)0x0000)
+
+/* TIM_Channel */
+#define TIM_Channel_1                      ((uint16_t)0x0000)
+#define TIM_Channel_2                      ((uint16_t)0x0004)
+#define TIM_Channel_3                      ((uint16_t)0x0008)
+#define TIM_Channel_4                      ((uint16_t)0x000C)
+
+/* TIM_Clock_Division_CKD */
+#define TIM_CKD_DIV1                       ((uint16_t)0x0000)
+#define TIM_CKD_DIV2                       ((uint16_t)0x0100)
+#define TIM_CKD_DIV4                       ((uint16_t)0x0200)
+
+/* TIM_Counter_Mode */
+#define TIM_CounterMode_Up                 ((uint16_t)0x0000)
+#define TIM_CounterMode_Down               ((uint16_t)0x0010)
+#define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020)
+#define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040)
+#define TIM_CounterMode_CenterAligned3     ((uint16_t)0x0060)
+
+/* TIM_Output_Compare_Polarity */
+#define TIM_OCPolarity_High                ((uint16_t)0x0000)
+#define TIM_OCPolarity_Low                 ((uint16_t)0x0002)
+
+/* TIM_Output_Compare_N_Polarity */
+#define TIM_OCNPolarity_High               ((uint16_t)0x0000)
+#define TIM_OCNPolarity_Low                ((uint16_t)0x0008)
+
+/* TIM_Output_Compare_state */
+#define TIM_OutputState_Disable            ((uint16_t)0x0000)
+#define TIM_OutputState_Enable             ((uint16_t)0x0001)
+
+/* TIM_Output_Compare_N_state */
+#define TIM_OutputNState_Disable           ((uint16_t)0x0000)
+#define TIM_OutputNState_Enable            ((uint16_t)0x0004)
+
+/* TIM_Capture_Compare_state */
+#define TIM_CCx_Enable                     ((uint16_t)0x0001)
+#define TIM_CCx_Disable                    ((uint16_t)0x0000)
+
+/* TIM_Capture_Compare_N_state */
+#define TIM_CCxN_Enable                    ((uint16_t)0x0004)
+#define TIM_CCxN_Disable                   ((uint16_t)0x0000)
+
+/* Break_Input_enable_disable */
+#define TIM_Break_Enable                   ((uint16_t)0x1000)
+#define TIM_Break_Disable                  ((uint16_t)0x0000)
+
+/* Break_Polarity */
+#define TIM_BreakPolarity_Low              ((uint16_t)0x0000)
+#define TIM_BreakPolarity_High             ((uint16_t)0x2000)
+
+/* TIM_AOE_Bit_Set_Reset */
+#define TIM_AutomaticOutput_Enable         ((uint16_t)0x4000)
+#define TIM_AutomaticOutput_Disable        ((uint16_t)0x0000)
+
+/* Lock_level */
+#define TIM_LOCKLevel_OFF                  ((uint16_t)0x0000)
+#define TIM_LOCKLevel_1                    ((uint16_t)0x0100)
+#define TIM_LOCKLevel_2                    ((uint16_t)0x0200)
+#define TIM_LOCKLevel_3                    ((uint16_t)0x0300)
+
+/* OSSI_Off_State_Selection_for_Idle_mode_state */
+#define TIM_OSSIState_Enable               ((uint16_t)0x0400)
+#define TIM_OSSIState_Disable              ((uint16_t)0x0000)
+
+/* OSSR_Off_State_Selection_for_Run_mode_state */
+#define TIM_OSSRState_Enable               ((uint16_t)0x0800)
+#define TIM_OSSRState_Disable              ((uint16_t)0x0000)
+
+/* TIM_Output_Compare_Idle_State */
+#define TIM_OCIdleState_Set                ((uint16_t)0x0100)
+#define TIM_OCIdleState_Reset              ((uint16_t)0x0000)
+
+/* TIM_Output_Compare_N_Idle_State */
+#define TIM_OCNIdleState_Set               ((uint16_t)0x0200)
+#define TIM_OCNIdleState_Reset             ((uint16_t)0x0000)
+
+/* TIM_Input_Capture_Polarity */
+#define TIM_ICPolarity_Rising              ((uint16_t)0x0000)
+#define TIM_ICPolarity_Falling             ((uint16_t)0x0002)
+#define TIM_ICPolarity_BothEdge            ((uint16_t)0x000A)
+
+/* TIM_Input_Capture_Selection */
+#define TIM_ICSelection_DirectTI           ((uint16_t)0x0001) /* TIM Input 1, 2, 3 or 4 is selected to be \
+                                                                 connected to IC1, IC2, IC3 or IC4, respectively */
+#define TIM_ICSelection_IndirectTI         ((uint16_t)0x0002) /* TIM Input 1, 2, 3 or 4 is selected to be \
+                                                                 connected to IC2, IC1, IC4 or IC3, respectively. */
+#define TIM_ICSelection_TRC                ((uint16_t)0x0003) /* TIM Input 1, 2, 3 or 4 is selected to be connected to TRC. */
+
+/* TIM_Input_Capture_Prescaler */
+#define TIM_ICPSC_DIV1                     ((uint16_t)0x0000) /* Capture performed each time an edge is detected on the capture input. */
+#define TIM_ICPSC_DIV2                     ((uint16_t)0x0004) /* Capture performed once every 2 events. */
+#define TIM_ICPSC_DIV4                     ((uint16_t)0x0008) /* Capture performed once every 4 events. */
+#define TIM_ICPSC_DIV8                     ((uint16_t)0x000C) /* Capture performed once every 8 events. */
+
+/* TIM_interrupt_sources */
+#define TIM_IT_Update                      ((uint16_t)0x0001)
+#define TIM_IT_CC1                         ((uint16_t)0x0002)
+#define TIM_IT_CC2                         ((uint16_t)0x0004)
+#define TIM_IT_CC3                         ((uint16_t)0x0008)
+#define TIM_IT_CC4                         ((uint16_t)0x0010)
+#define TIM_IT_COM                         ((uint16_t)0x0020)
+#define TIM_IT_Trigger                     ((uint16_t)0x0040)
+#define TIM_IT_Break                       ((uint16_t)0x0080)
+
+/* TIM_DMA_Base_address */
+#define TIM_DMABase_CR1                    ((uint16_t)0x0000)
+#define TIM_DMABase_CR2                    ((uint16_t)0x0001)
+#define TIM_DMABase_SMCR                   ((uint16_t)0x0002)
+#define TIM_DMABase_DIER                   ((uint16_t)0x0003)
+#define TIM_DMABase_SR                     ((uint16_t)0x0004)
+#define TIM_DMABase_EGR                    ((uint16_t)0x0005)
+#define TIM_DMABase_CCMR1                  ((uint16_t)0x0006)
+#define TIM_DMABase_CCMR2                  ((uint16_t)0x0007)
+#define TIM_DMABase_CCER                   ((uint16_t)0x0008)
+#define TIM_DMABase_CNT                    ((uint16_t)0x0009)
+#define TIM_DMABase_PSC                    ((uint16_t)0x000A)
+#define TIM_DMABase_ARR                    ((uint16_t)0x000B)
+#define TIM_DMABase_RCR                    ((uint16_t)0x000C)
+#define TIM_DMABase_CCR1                   ((uint16_t)0x000D)
+#define TIM_DMABase_CCR2                   ((uint16_t)0x000E)
+#define TIM_DMABase_CCR3                   ((uint16_t)0x000F)
+#define TIM_DMABase_CCR4                   ((uint16_t)0x0010)
+#define TIM_DMABase_BDTR                   ((uint16_t)0x0011)
+#define TIM_DMABase_DCR                    ((uint16_t)0x0012)
+
+/* TIM_DMA_Burst_Length */
+#define TIM_DMABurstLength_1Transfer       ((uint16_t)0x0000)
+#define TIM_DMABurstLength_2Transfers      ((uint16_t)0x0100)
+#define TIM_DMABurstLength_3Transfers      ((uint16_t)0x0200)
+#define TIM_DMABurstLength_4Transfers      ((uint16_t)0x0300)
+#define TIM_DMABurstLength_5Transfers      ((uint16_t)0x0400)
+#define TIM_DMABurstLength_6Transfers      ((uint16_t)0x0500)
+#define TIM_DMABurstLength_7Transfers      ((uint16_t)0x0600)
+#define TIM_DMABurstLength_8Transfers      ((uint16_t)0x0700)
+#define TIM_DMABurstLength_9Transfers      ((uint16_t)0x0800)
+#define TIM_DMABurstLength_10Transfers     ((uint16_t)0x0900)
+#define TIM_DMABurstLength_11Transfers     ((uint16_t)0x0A00)
+#define TIM_DMABurstLength_12Transfers     ((uint16_t)0x0B00)
+#define TIM_DMABurstLength_13Transfers     ((uint16_t)0x0C00)
+#define TIM_DMABurstLength_14Transfers     ((uint16_t)0x0D00)
+#define TIM_DMABurstLength_15Transfers     ((uint16_t)0x0E00)
+#define TIM_DMABurstLength_16Transfers     ((uint16_t)0x0F00)
+#define TIM_DMABurstLength_17Transfers     ((uint16_t)0x1000)
+#define TIM_DMABurstLength_18Transfers     ((uint16_t)0x1100)
+
+/* TIM_DMA_sources */
+#define TIM_DMA_Update                     ((uint16_t)0x0100)
+#define TIM_DMA_CC1                        ((uint16_t)0x0200)
+#define TIM_DMA_CC2                        ((uint16_t)0x0400)
+#define TIM_DMA_CC3                        ((uint16_t)0x0800)
+#define TIM_DMA_CC4                        ((uint16_t)0x1000)
+#define TIM_DMA_COM                        ((uint16_t)0x2000)
+#define TIM_DMA_Trigger                    ((uint16_t)0x4000)
+
+/* TIM_External_Trigger_Prescaler */
+#define TIM_ExtTRGPSC_OFF                  ((uint16_t)0x0000)
+#define TIM_ExtTRGPSC_DIV2                 ((uint16_t)0x1000)
+#define TIM_ExtTRGPSC_DIV4                 ((uint16_t)0x2000)
+#define TIM_ExtTRGPSC_DIV8                 ((uint16_t)0x3000)
+
+/* TIM_Internal_Trigger_Selection */
+#define TIM_TS_ITR0                        ((uint16_t)0x0000)
+#define TIM_TS_ITR1                        ((uint16_t)0x0010)
+#define TIM_TS_ITR2                        ((uint16_t)0x0020)
+#define TIM_TS_ITR3                        ((uint16_t)0x0030)
+#define TIM_TS_TI1F_ED                     ((uint16_t)0x0040)
+#define TIM_TS_TI1FP1                      ((uint16_t)0x0050)
+#define TIM_TS_TI2FP2                      ((uint16_t)0x0060)
+#define TIM_TS_ETRF                        ((uint16_t)0x0070)
+
+/* TIM_TIx_External_Clock_Source */
+#define TIM_TIxExternalCLK1Source_TI1      ((uint16_t)0x0050)
+#define TIM_TIxExternalCLK1Source_TI2      ((uint16_t)0x0060)
+#define TIM_TIxExternalCLK1Source_TI1ED    ((uint16_t)0x0040)
+
+/* TIM_External_Trigger_Polarity */
+#define TIM_ExtTRGPolarity_Inverted        ((uint16_t)0x8000)
+#define TIM_ExtTRGPolarity_NonInverted     ((uint16_t)0x0000)
+
+/* TIM_Prescaler_Reload_Mode */
+#define TIM_PSCReloadMode_Update           ((uint16_t)0x0000)
+#define TIM_PSCReloadMode_Immediate        ((uint16_t)0x0001)
+
+/* TIM_Forced_Action */
+#define TIM_ForcedAction_Active            ((uint16_t)0x0050)
+#define TIM_ForcedAction_InActive          ((uint16_t)0x0040)
+
+/* TIM_Encoder_Mode */
+#define TIM_EncoderMode_TI1                ((uint16_t)0x0001)
+#define TIM_EncoderMode_TI2                ((uint16_t)0x0002)
+#define TIM_EncoderMode_TI12               ((uint16_t)0x0003)
+
+/* TIM_Event_Source */
+#define TIM_EventSource_Update             ((uint16_t)0x0001)
+#define TIM_EventSource_CC1                ((uint16_t)0x0002)
+#define TIM_EventSource_CC2                ((uint16_t)0x0004)
+#define TIM_EventSource_CC3                ((uint16_t)0x0008)
+#define TIM_EventSource_CC4                ((uint16_t)0x0010)
+#define TIM_EventSource_COM                ((uint16_t)0x0020)
+#define TIM_EventSource_Trigger            ((uint16_t)0x0040)
+#define TIM_EventSource_Break              ((uint16_t)0x0080)
+
+/* TIM_Update_Source */
+#define TIM_UpdateSource_Global            ((uint16_t)0x0000) /* Source of update is the counter overflow/underflow \
+                                                                 or the setting of UG bit, or an update generation  \
+                                                                 through the slave mode controller. */
+#define TIM_UpdateSource_Regular           ((uint16_t)0x0001) /* Source of update is counter overflow/underflow. */
+
+/* TIM_Output_Compare_Preload_State */
+#define TIM_OCPreload_Enable               ((uint16_t)0x0008)
+#define TIM_OCPreload_Disable              ((uint16_t)0x0000)
+
+/* TIM_Output_Compare_Fast_State */
+#define TIM_OCFast_Enable                  ((uint16_t)0x0004)
+#define TIM_OCFast_Disable                 ((uint16_t)0x0000)
+
+/* TIM_Output_Compare_Clear_State */
+#define TIM_OCClear_Enable                 ((uint16_t)0x0080)
+#define TIM_OCClear_Disable                ((uint16_t)0x0000)
+
+/* TIM_Trigger_Output_Source */
+#define TIM_TRGOSource_Reset               ((uint16_t)0x0000)
+#define TIM_TRGOSource_Enable              ((uint16_t)0x0010)
+#define TIM_TRGOSource_Update              ((uint16_t)0x0020)
+#define TIM_TRGOSource_OC1                 ((uint16_t)0x0030)
+#define TIM_TRGOSource_OC1Ref              ((uint16_t)0x0040)
+#define TIM_TRGOSource_OC2Ref              ((uint16_t)0x0050)
+#define TIM_TRGOSource_OC3Ref              ((uint16_t)0x0060)
+#define TIM_TRGOSource_OC4Ref              ((uint16_t)0x0070)
+
+/* TIM_Slave_Mode */
+#define TIM_SlaveMode_Reset                ((uint16_t)0x0004)
+#define TIM_SlaveMode_Gated                ((uint16_t)0x0005)
+#define TIM_SlaveMode_Trigger              ((uint16_t)0x0006)
+#define TIM_SlaveMode_External1            ((uint16_t)0x0007)
+
+/* TIM_Master_Slave_Mode */
+#define TIM_MasterSlaveMode_Enable         ((uint16_t)0x0080)
+#define TIM_MasterSlaveMode_Disable        ((uint16_t)0x0000)
+
+/* TIM_Flags */
+#define TIM_FLAG_Update                    ((uint16_t)0x0001)
+#define TIM_FLAG_CC1                       ((uint16_t)0x0002)
+#define TIM_FLAG_CC2                       ((uint16_t)0x0004)
+#define TIM_FLAG_CC3                       ((uint16_t)0x0008)
+#define TIM_FLAG_CC4                       ((uint16_t)0x0010)
+#define TIM_FLAG_COM                       ((uint16_t)0x0020)
+#define TIM_FLAG_Trigger                   ((uint16_t)0x0040)
+#define TIM_FLAG_Break                     ((uint16_t)0x0080)
+#define TIM_FLAG_CC1OF                     ((uint16_t)0x0200)
+#define TIM_FLAG_CC2OF                     ((uint16_t)0x0400)
+#define TIM_FLAG_CC3OF                     ((uint16_t)0x0800)
+#define TIM_FLAG_CC4OF                     ((uint16_t)0x1000)
+
+/* TIM_Legacy */
+#define TIM_DMABurstLength_1Byte           TIM_DMABurstLength_1Transfer
+#define TIM_DMABurstLength_2Bytes          TIM_DMABurstLength_2Transfers
+#define TIM_DMABurstLength_3Bytes          TIM_DMABurstLength_3Transfers
+#define TIM_DMABurstLength_4Bytes          TIM_DMABurstLength_4Transfers
+#define TIM_DMABurstLength_5Bytes          TIM_DMABurstLength_5Transfers
+#define TIM_DMABurstLength_6Bytes          TIM_DMABurstLength_6Transfers
+#define TIM_DMABurstLength_7Bytes          TIM_DMABurstLength_7Transfers
+#define TIM_DMABurstLength_8Bytes          TIM_DMABurstLength_8Transfers
+#define TIM_DMABurstLength_9Bytes          TIM_DMABurstLength_9Transfers
+#define TIM_DMABurstLength_10Bytes         TIM_DMABurstLength_10Transfers
+#define TIM_DMABurstLength_11Bytes         TIM_DMABurstLength_11Transfers
+#define TIM_DMABurstLength_12Bytes         TIM_DMABurstLength_12Transfers
+#define TIM_DMABurstLength_13Bytes         TIM_DMABurstLength_13Transfers
+#define TIM_DMABurstLength_14Bytes         TIM_DMABurstLength_14Transfers
+#define TIM_DMABurstLength_15Bytes         TIM_DMABurstLength_15Transfers
+#define TIM_DMABurstLength_16Bytes         TIM_DMABurstLength_16Transfers
+#define TIM_DMABurstLength_17Bytes         TIM_DMABurstLength_17Transfers
+#define TIM_DMABurstLength_18Bytes         TIM_DMABurstLength_18Transfers
+
+
+/* ch32v00x_usart.h ----------------------------------------------------------*/
+
+/* USART_Word_Length */
+#define USART_WordLength_8b                  ((uint16_t)0x0000)
+#define USART_WordLength_9b                  ((uint16_t)0x1000)
+
+/* USART_Stop_Bits */
+#define USART_StopBits_1                     ((uint16_t)0x0000)
+#define USART_StopBits_0_5                   ((uint16_t)0x1000)
+#define USART_StopBits_2                     ((uint16_t)0x2000)
+#define USART_StopBits_1_5                   ((uint16_t)0x3000)
+
+/* USART_Parity */
+#define USART_Parity_No                      ((uint16_t)0x0000)
+#define USART_Parity_Even                    ((uint16_t)0x0400)
+#define USART_Parity_Odd                     ((uint16_t)0x0600)
+
+/* USART_Mode */
+#define USART_Mode_Rx                        ((uint16_t)0x0004)
+#define USART_Mode_Tx                        ((uint16_t)0x0008)
+
+/* USART_Hardware_Flow_Control */
+#define USART_HardwareFlowControl_None       ((uint16_t)0x0000)
+#define USART_HardwareFlowControl_RTS        ((uint16_t)0x0100)
+#define USART_HardwareFlowControl_CTS        ((uint16_t)0x0200)
+#define USART_HardwareFlowControl_RTS_CTS    ((uint16_t)0x0300)
+
+/* USART_Clock */
+#define USART_Clock_Disable                  ((uint16_t)0x0000)
+#define USART_Clock_Enable                   ((uint16_t)0x0800)
+
+/* USART_Clock_Polarity */
+#define USART_CPOL_Low                       ((uint16_t)0x0000)
+#define USART_CPOL_High                      ((uint16_t)0x0400)
+
+/* USART_Clock_Phase */
+#define USART_CPHA_1Edge                     ((uint16_t)0x0000)
+#define USART_CPHA_2Edge                     ((uint16_t)0x0200)
+
+/* USART_Last_Bit */
+#define USART_LastBit_Disable                ((uint16_t)0x0000)
+#define USART_LastBit_Enable                 ((uint16_t)0x0100)
+
+/* USART_Interrupt_definition */
+#define USART_IT_PE                          ((uint16_t)0x0028)
+#define USART_IT_TXE                         ((uint16_t)0x0727)
+#define USART_IT_TC                          ((uint16_t)0x0626)
+#define USART_IT_RXNE                        ((uint16_t)0x0525)
+#define USART_IT_ORE_RX                      ((uint16_t)0x0325)
+#define USART_IT_IDLE                        ((uint16_t)0x0424)
+#define USART_IT_LBD                         ((uint16_t)0x0846)
+#define USART_IT_CTS                         ((uint16_t)0x096A)
+#define USART_IT_ERR                         ((uint16_t)0x0060)
+#define USART_IT_ORE_ER                      ((uint16_t)0x0360)
+#define USART_IT_NE                          ((uint16_t)0x0260)
+#define USART_IT_FE                          ((uint16_t)0x0160)
+
+#define USART_IT_ORE                         USART_IT_ORE_ER
+
+/* USART_DMA_Requests */
+#define USART_DMAReq_Tx                      ((uint16_t)0x0080)
+#define USART_DMAReq_Rx                      ((uint16_t)0x0040)
+
+/* USART_WakeUp_methods */
+#define USART_WakeUp_IdleLine                ((uint16_t)0x0000)
+#define USART_WakeUp_AddressMark             ((uint16_t)0x0800)
+
+/* USART_LIN_Break_Detection_Length */
+#define USART_LINBreakDetectLength_10b       ((uint16_t)0x0000)
+#define USART_LINBreakDetectLength_11b       ((uint16_t)0x0020)
+
+/* USART_IrDA_Low_Power */
+#define USART_IrDAMode_LowPower              ((uint16_t)0x0004)
+#define USART_IrDAMode_Normal                ((uint16_t)0x0000)
+
+/* USART_Flags */
+#define USART_FLAG_CTS                       ((uint16_t)0x0200)
+#define USART_FLAG_LBD                       ((uint16_t)0x0100)
+#define USART_FLAG_TXE                       ((uint16_t)0x0080)
+#define USART_FLAG_TC                        ((uint16_t)0x0040)
+#define USART_FLAG_RXNE                      ((uint16_t)0x0020)
+#define USART_FLAG_IDLE                      ((uint16_t)0x0010)
+#define USART_FLAG_ORE                       ((uint16_t)0x0008)
+#define USART_FLAG_NE                        ((uint16_t)0x0004)
+#define USART_FLAG_FE                        ((uint16_t)0x0002)
+#define USART_FLAG_PE                        ((uint16_t)0x0001)
+
+/* ch32v00x_wwdg.h -----------------------------------------------------------*/
+
+
+/* WWDG_Prescaler */
+#define WWDG_Prescaler_1    ((uint32_t)0x00000000)
+#define WWDG_Prescaler_2    ((uint32_t)0x00000080)
+#define WWDG_Prescaler_4    ((uint32_t)0x00000100)
+#define WWDG_Prescaler_8    ((uint32_t)0x00000180)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __CH32V00x_CONF_H */
+
+
+	
+///////////////////////////////////////////////////////////////////////////////////////////////	
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef __CORE_RISCV_H__
+#define __CORE_RISCV_H__
+
+#include <stdint.h>
+
+/* define compiler specific symbols */
+#if defined(__CC_ARM)
+  #define __ASM       __asm     /*!< asm keyword for ARM Compiler          */
+  #define __INLINE    __inline  /*!< inline keyword for ARM Compiler       */
+
+#elif defined(__ICCARM__)
+  #define __ASM       __asm   /*!< asm keyword for IAR Compiler          */
+  #define __INLINE    inline  /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
+
+#elif defined(__GNUC__)
+  #define __ASM       __asm   /*!< asm keyword for GNU Compiler          */
+  #define __INLINE    inline  /*!< inline keyword for GNU Compiler       */
+
+#elif defined(__TASKING__)
+  #define __ASM       __asm   /*!< asm keyword for TASKING Compiler      */
+  #define __INLINE    inline  /*!< inline keyword for TASKING Compiler   */
+
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+	
+/* Standard Peripheral Library old types (maintained for legacy purpose) */
+typedef __I uint32_t vuc32;  /* Read Only */
+typedef __I uint16_t vuc16;  /* Read Only */
+typedef __I uint8_t vuc8;   /* Read Only */
+
+typedef const uint32_t uc32;  /* Read Only */
+typedef const uint16_t uc16;  /* Read Only */
+typedef const uint8_t uc8;   /* Read Only */
+
+typedef __I int32_t vsc32;  /* Read Only */
+typedef __I int16_t vsc16;  /* Read Only */
+typedef __I int8_t vsc8;   /* Read Only */
+
+typedef const int32_t sc32;  /* Read Only */
+typedef const int16_t sc16;  /* Read Only */
+typedef const int8_t sc8;   /* Read Only */
+
+typedef __IO uint32_t  vu32;
+typedef __IO uint16_t vu16;
+typedef __IO uint8_t  vu8;
+
+typedef uint32_t  u32;
+typedef uint16_t u16;
+typedef uint8_t  u8;
+
+typedef __IO int32_t  vs32;
+typedef __IO int16_t  vs16;
+typedef __IO int8_t   vs8;
+
+typedef int32_t  s32;
+typedef int16_t s16;
+typedef int8_t  s8;
+
+typedef enum {NoREADY = 0, READY = !NoREADY} ErrorStatus;
+
+typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
+
+typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
+
+#define   RV_STATIC_INLINE  static  inline
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct{
+    __I  uint32_t ISR[8];
+    __I  uint32_t IPR[8];
+    __IO uint32_t ITHRESDR;
+    __IO uint32_t RESERVED;
+    __IO uint32_t CFGR;
+    __I  uint32_t GISR;
+    __IO uint8_t VTFIDR[4];
+    uint8_t RESERVED0[12];
+    __IO uint32_t VTFADDR[4];
+    uint8_t RESERVED1[0x90];
+    __O  uint32_t IENR[8];
+    uint8_t RESERVED2[0x60];
+    __O  uint32_t IRER[8];
+    uint8_t RESERVED3[0x60];
+    __O  uint32_t IPSR[8];
+    uint8_t RESERVED4[0x60];
+    __O  uint32_t IPRR[8];
+    uint8_t RESERVED5[0x60];
+    __IO uint32_t IACTR[8];
+    uint8_t RESERVED6[0xE0];
+    __IO uint8_t IPRIOR[256];
+    uint8_t RESERVED7[0x810];
+    __IO uint32_t SCTLR;
+}PFIC_Type;
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+    __IO uint32_t CTLR;
+    __IO uint32_t SR;
+    __IO uint32_t CNT;
+    uint32_t RESERVED0;
+    __IO uint32_t CMP;
+    uint32_t RESERVED1;
+}SysTick_Type;
+
+
+#define PFIC            ((PFIC_Type *) 0xE000E000 )
+#define NVIC            PFIC
+#define NVIC_KEY1       ((uint32_t)0xFA050000)
+#define	NVIC_KEY2	    ((uint32_t)0xBCAF0000)
+#define	NVIC_KEY3		((uint32_t)0xBEEF0000)
+
+#define SysTick         ((SysTick_Type *) 0xE000F000)
+
+
+/*********************************************************************
+ * @fn      __enable_irq
+ *
+ * @brief   Enable Global Interrupt
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __enable_irq()
+{
+  uint32_t result;
+
+  __asm volatile("csrr %0," "mstatus": "=r"(result));
+  result |= 0x88;
+  __asm volatile ("csrw mstatus, %0" : : "r" (result) );
+}
+
+/*********************************************************************
+ * @fn      __disable_irq
+ *
+ * @brief   Disable Global Interrupt
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __disable_irq()
+{
+  uint32_t result;
+
+  __asm volatile("csrr %0," "mstatus": "=r"(result));
+  result &= ~0x88;
+  __asm volatile ("csrw mstatus, %0" : : "r" (result) );
+}
+
+/*********************************************************************
+ * @fn      __NOP
+ *
+ * @brief   nop
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void __NOP()
+{
+  __asm volatile ("nop");
+}
+
+/*********************************************************************
+ * @fn       NVIC_EnableIRQ
+ *
+ * @brief   Disable Interrupt
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
+{
+  NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn       NVIC_DisableIRQ
+ *
+ * @brief   Disable Interrupt
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
+{
+  NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn       NVIC_GetStatusIRQ
+ *
+ * @brief   Get Interrupt Enable State
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  1 - 1: Interrupt Pending Enable
+ *                0 - Interrupt Pending Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn)
+{
+  return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_GetPendingIRQ
+ *
+ * @brief   Get Interrupt Pending State
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  1 - 1: Interrupt Pending Enable
+ *                0 - Interrupt Pending Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
+{
+  return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_SetPendingIRQ
+ *
+ * @brief   Set Interrupt Pending
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
+{
+  NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_ClearPendingIRQ
+ *
+ * @brief   Clear Interrupt Pending
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
+{
+  NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn      NVIC_GetActive
+ *
+ * @brief   Get Interrupt Active State
+ *
+ * @param   IRQn - Interrupt Numbers
+ *
+ * @return  1 - Interrupt Active
+ *                0 - Interrupt No Active
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
+{
+  return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn      NVIC_SetPriority
+ *
+ * @brief   Set Interrupt Priority
+ *
+ * @param   IRQn - Interrupt Numbers
+ *          priority: bit7 - pre-emption priority
+ *                    bit6 - subpriority
+ *                    bit[5-0] - reserved
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
+{
+  NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
+}
+
+/*********************************************************************
+ * @fn       __WFI
+ *
+ * @brief   Wait for Interrupt
+ *
+ * @return  none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void)
+{
+  NVIC->SCTLR &= ~(1<<3);   // wfi
+  asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn       __WFE
+ *
+ * @brief   Wait for Events
+ *
+ * @return  none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
+{
+  uint32_t t;
+
+  t = NVIC->SCTLR;
+  NVIC->SCTLR |= (1<<3)|(1<<5);     // (wfi->wfe)+(__sev)
+  NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
+  asm volatile ("wfi");
+  asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn      SetVTFIRQ
+ *
+ * @brief   Set VTF Interrupt
+ *
+ * @param   addr - VTF interrupt service function base address.
+ *                  IRQn - Interrupt Numbers
+ *                  num - VTF Interrupt Numbers
+ *                  NewState -  DISABLE or ENABLE
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){
+  if(num > 1)  return ;
+
+  if (NewState != DISABLE)
+  {
+      NVIC->VTFIDR[num] = IRQn;
+      NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1);
+  }
+  else{
+      NVIC->VTFIDR[num] = IRQn;
+      NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1));
+  }
+}
+
+/*********************************************************************
+ * @fn       NVIC_SystemReset
+ *
+ * @brief   Initiate a system reset request
+ *
+ * @return  none
+ */
+RV_STATIC_INLINE void NVIC_SystemReset(void)
+{
+  NVIC->CFGR = NVIC_KEY3|(1<<7);
+}
+
+
+
+/*********************************************************************
+ * @fn      __get_MSTATUS
+ *
+ * @brief   Return the Machine Status Register
+ *
+ * @return  mstatus value
+ */
+static inline uint32_t __get_MSTATUS(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0," "mstatus": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MSTATUS
+ *
+ * @brief   Set the Machine Status Register
+ *
+ * @param   value  - set mstatus value
+ *
+ * @return  none
+ */
+static inline void __set_MSTATUS(uint32_t value)
+{
+    __ASM volatile("csrw mstatus, %0" : : "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MISA
+ *
+ * @brief   Return the Machine ISA Register
+ *
+ * @return  misa value
+ */
+static inline uint32_t __get_MISA(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0,""misa" : "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MISA
+ *
+ * @brief   Set the Machine ISA Register
+ *
+ * @param   value  - set misa value
+ *
+ * @return  none
+ */
+static inline void __set_MISA(uint32_t value)
+{
+    __ASM volatile("csrw misa, %0" : : "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MTVEC
+ *
+ * @brief   Return the Machine Trap-Vector Base-Address Register
+ *
+ * @return  mtvec value
+ */
+static inline uint32_t __get_MTVEC(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0," "mtvec": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MTVEC
+ *
+ * @brief   Set the Machine Trap-Vector Base-Address Register
+ *
+ * @param   value  - set mtvec value
+ *
+ * @return  none
+ */
+static inline void __set_MTVEC(uint32_t value)
+{
+    __ASM volatile("csrw mtvec, %0":: "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MSCRATCH
+ *
+ * @brief   Return the Machine Seratch Register
+ *
+ * @return  mscratch value
+ */
+static inline uint32_t __get_MSCRATCH(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0," "mscratch" : "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MSCRATCH
+ *
+ * @brief   Set the Machine Seratch Register
+ *
+ * @param   value  - set mscratch value
+ *
+ * @return  none
+ */
+static inline void __set_MSCRATCH(uint32_t value)
+{
+    __ASM volatile("csrw mscratch, %0" : : "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MEPC
+ *
+ * @brief   Return the Machine Exception Program Register
+ *
+ * @return  mepc value
+ */
+static inline uint32_t __get_MEPC(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0," "mepc" : "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MEPC
+ *
+ * @brief   Set the Machine Exception Program Register
+ *
+ * @return  mepc value
+ */
+static inline void __set_MEPC(uint32_t value)
+{
+    __ASM volatile("csrw mepc, %0" : : "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MCAUSE
+ *
+ * @brief   Return the Machine Cause Register
+ *
+ * @return  mcause value
+ */
+static inline uint32_t __get_MCAUSE(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0," "mcause": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __set_MCAUSE
+ *
+ * @brief   Set the Machine Cause Register
+ *
+ * @return  mcause value
+ */
+static inline void __set_MCAUSE(uint32_t value)
+{
+    __ASM volatile("csrw mcause, %0":: "r"(value));
+}
+
+/*********************************************************************
+ * @fn      __get_MVENDORID
+ *
+ * @brief   Return Vendor ID Register
+ *
+ * @return  mvendorid value
+ */
+static inline uint32_t __get_MVENDORID(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0,""mvendorid": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __get_MARCHID
+ *
+ * @brief   Return Machine Architecture ID Register
+ *
+ * @return  marchid value
+ */
+static inline uint32_t __get_MARCHID(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0,""marchid": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __get_MIMPID
+ *
+ * @brief   Return Machine Implementation ID Register
+ *
+ * @return  mimpid value
+ */
+static inline uint32_t __get_MIMPID(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0,""mimpid": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __get_MHARTID
+ *
+ * @brief   Return Hart ID Register
+ *
+ * @return  mhartid value
+ */
+static inline uint32_t __get_MHARTID(void)
+{
+    uint32_t result;
+
+    __ASM volatile("csrr %0,""mhartid": "=r"(result));
+    return (result);
+}
+
+/*********************************************************************
+ * @fn      __get_SP
+ *
+ * @brief   Return SP Register
+ *
+ * @return  SP value
+ */
+static inline uint32_t __get_SP(void)
+{
+    uint32_t result;
+
+    __ASM volatile("mv %0,""sp": "=r"(result):);
+    return (result);
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/* __CORE_RISCV_H__ */
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef _CH32V003_MISC
+#define _CH32V003_MISC
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DELAY_US_TIME (SYSTEM_CORE_CLOCK / 8000000)
+#define DELAY_MS_TIME (SYSTEM_CORE_CLOCK / 8000)
+
+void DelaySysTick( uint32_t n );
+
+#define Delay_Us(n) DelaySysTick( n * DELAY_US_TIME )
+#define Delay_Ms(n) DelaySysTick( n * DELAY_MS_TIME )
+
+// Tricky: We need to make sure main and SystemInit() are preserved.
+int main() __attribute__((used));
+void SystemInit(void) __attribute__((used));
+
+// Useful functions
+void SystemInit48HSI( void );
+
+#define UART_BAUD_RATE 115200
+#define OVER8DIV 4
+#define INTEGER_DIVIDER (((25 * (APB_CLOCK)) / ((OVER8DIV) * (UART_BAUD_RATE))))
+#define FRACTIONAL_DIVIDER ((INTEGER_DIVIDER)%100)
+#define UART_BRR ((((INTEGER_DIVIDER) / 100) << 4) | (((((FRACTIONAL_DIVIDER) * ((OVER8DIV)*2)) + 50)/100)&7))
+// Put an output debug UART on Pin D5.
+// You can write to this with printf(...) or puts(...)
+// Call with SetupUART( UART_BRR )
+void SetupUART( int uartBRR );
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/ch32v003fun/ch32v003fun.ld b/ch32v003fun/ch32v003fun.ld
new file mode 100644
index 0000000000000000000000000000000000000000..d3d27288f1530e420dafd11ea17d1c93401890c9
--- /dev/null
+++ b/ch32v003fun/ch32v003fun.ld
@@ -0,0 +1,159 @@
+ENTRY( InterruptVector )
+
+__stack_size = 256;
+
+PROVIDE( _stack_size = __stack_size );
+
+MEMORY
+{
+	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
+	RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 2K
+}
+
+SECTIONS
+{
+    .init :
+    { 
+      _sinit = .;
+      . = ALIGN(4);
+      KEEP(*(SORT_NONE(.init)))
+      . = ALIGN(4);
+      _einit = .;
+    } >FLASH AT>FLASH
+
+    .text :
+    {
+      . = ALIGN(4);
+      *(.text)
+      *(.text.*)
+      *(.rodata)
+      *(.rodata*)
+      *(.gnu.linkonce.t.*)
+      . = ALIGN(4);
+    } >FLASH AT>FLASH 
+
+    .fini :
+    {
+      KEEP(*(SORT_NONE(.fini)))
+      . = ALIGN(4);
+    } >FLASH AT>FLASH
+
+    PROVIDE( _etext = . );
+    PROVIDE( _eitcm = . );  
+
+    .preinit_array :
+    {
+      PROVIDE_HIDDEN (__preinit_array_start = .);
+      KEEP (*(.preinit_array))
+      PROVIDE_HIDDEN (__preinit_array_end = .);
+    } >FLASH AT>FLASH 
+  
+    .init_array :
+    {
+      PROVIDE_HIDDEN (__init_array_start = .);
+      KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+      KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
+      PROVIDE_HIDDEN (__init_array_end = .);
+    } >FLASH AT>FLASH 
+  
+    .fini_array :
+    {
+      PROVIDE_HIDDEN (__fini_array_start = .);
+      KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+      KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
+      PROVIDE_HIDDEN (__fini_array_end = .);
+    } >FLASH AT>FLASH 
+  
+    .ctors :
+    {
+      /* gcc uses crtbegin.o to find the start of
+         the constructors, so we make sure it is
+         first.  Because this is a wildcard, it
+         doesn't matter if the user does not
+         actually link against crtbegin.o; the
+         linker won't look for a file to match a
+         wildcard.  The wildcard also means that it
+         doesn't matter which directory crtbegin.o
+         is in.  */
+      KEEP (*crtbegin.o(.ctors))
+      KEEP (*crtbegin?.o(.ctors))
+      /* We don't want to include the .ctor section from
+         the crtend.o file until after the sorted ctors.
+         The .ctor section from the crtend file contains the
+         end of ctors marker and it must be last */
+      KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
+      KEEP (*(SORT(.ctors.*)))
+      KEEP (*(.ctors))
+    } >FLASH AT>FLASH 
+  
+    .dtors :
+    {
+      KEEP (*crtbegin.o(.dtors))
+      KEEP (*crtbegin?.o(.dtors))
+      KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
+      KEEP (*(SORT(.dtors.*)))
+      KEEP (*(.dtors))
+    } >FLASH AT>FLASH 
+
+    .dalign :
+    {
+      . = ALIGN(4);
+      PROVIDE(_data_vma = .);
+    } >RAM AT>FLASH  
+
+    .dlalign :
+    {
+      . = ALIGN(4); 
+      PROVIDE(_data_lma = .);
+    } >FLASH AT>FLASH
+
+    .data :
+    {
+      . = ALIGN(4);
+      *(.gnu.linkonce.r.*)
+      *(.data .data.*)
+      *(.gnu.linkonce.d.*)
+      . = ALIGN(8);
+      PROVIDE( __global_pointer$ = . + 0x800 );
+      *(.sdata .sdata.*)
+      *(.sdata2*)
+      *(.gnu.linkonce.s.*)
+      . = ALIGN(8);
+      *(.srodata.cst16)
+      *(.srodata.cst8)
+      *(.srodata.cst4)
+      *(.srodata.cst2)
+      *(.srodata .srodata.*)
+      . = ALIGN(4);
+      PROVIDE( _edata = .);
+    } >RAM AT>FLASH
+
+    .bss :
+    {
+      . = ALIGN(4);
+      PROVIDE( _sbss = .);
+      *(.sbss*)
+      *(.gnu.linkonce.sb.*)
+      *(.bss*)
+      *(.gnu.linkonce.b.*)    
+      *(COMMON*)
+      . = ALIGN(4);
+      PROVIDE( _ebss = .);
+    } >RAM AT>FLASH
+
+    PROVIDE( _end = _ebss);
+	PROVIDE( end = . );
+
+	.stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
+	{
+	    PROVIDE( _heap_end = . );
+	    . = ALIGN(4);
+	    PROVIDE(_susrstack = . );
+	    . = . + __stack_size;
+	    PROVIDE( _eusrstack = .);
+	} >RAM 
+	
+}
+
+
+
diff --git a/examples/blink/Makefile b/examples/blink/Makefile
index 8889c67f4775cf470ccbb3eaacb11efa1d8b8e09..0a4310763ff6d7bf7217bf4c8605f652274616fd 100644
--- a/examples/blink/Makefile
+++ b/examples/blink/Makefile
@@ -7,21 +7,31 @@ PREFIX:=riscv64-unknown-elf
 GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
 
 EVT:=../../ch32v003evt
+
 MINICHLINK:=../../minichlink
 
+ifeq ($(OS),Windows_NT)
+# On Windows, all the major RISC-V GCC installs are missing the -ec libgcc.
+LIB_GCC=../../misc/libgcc.a
+else
+LIB_GCC=-lgcc
+endif
+
+CH32V003FUN:=../../ch32v003fun
+
 CFLAGS:= \
 	-g -Os -flto -ffunction-sections \
-	-static-libgcc -lgcc \
+	-static-libgcc $(LIB_GCC) \
 	-march=rv32ec \
 	-mabi=ilp32e \
 	-I/usr/include/newlib \
-	-I$(EVT) \
+	-I$(CH32V003FUN) \
 	-nostdlib \
 	-I.
 
-LDFLAGS:=-T $(EVT)/ch32v003.ld -Wl,--gc-sections
+LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections
 
-SYSTEM_C:=$(EVT)/startup_ch32v003.c $(EVT)/embedlibc.c
+SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
 
 $(TARGET).elf : $(SYSTEM_C) $(TARGET).c
 	$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
@@ -34,7 +44,6 @@ $(TARGET).bin : $(TARGET).elf
 	$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
 
 flash : $(TARGET).bin
-	make -C $(MINICHLINK) all
 	$(MINICHLINK)/minichlink -w $< -r
 
 clean :
diff --git a/examples/blink/blink.bin b/examples/blink/blink.bin
new file mode 100644
index 0000000000000000000000000000000000000000..e22d2b54b66c603299ca02592e7849815ac9ac9e
Binary files /dev/null and b/examples/blink/blink.bin differ
diff --git a/examples/blink/blink.c b/examples/blink/blink.c
index e99ce3f3e8bf5141451be8caf9249266c6c8267a..9b99747755972c996826b2746e9da96746a4f782 100644
--- a/examples/blink/blink.c
+++ b/examples/blink/blink.c
@@ -1,11 +1,13 @@
 // Could be defined here, or in the processor defines.
 #define SYSTEM_CORE_CLOCK 48000000
 
-#include "ch32v00x.h"
+#include "ch32v003fun.h"
 #include <stdio.h>
 
 #define APB_CLOCK SYSTEM_CORE_CLOCK
 
+uint32_t count;
+
 int main()
 {
 	SystemInit48HSI();
@@ -17,11 +19,15 @@ int main()
 	GPIOD->CFGLR &= ~(0xf<<(4*0));
 	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*0);
 
+	GPIOD->CFGLR &= ~(0xf<<(4*4));
+	GPIOD->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP)<<(4*4);
+
 	while(1)
 	{
-		GPIOD->BSHR = 1;	 // Turn on GPIOD0
+		GPIOD->BSHR = (1<<0) | (1<<4);	 // Turn on GPIOD0
 		Delay_Ms( 100 );
-		GPIOD->BSHR = 1<<16; // Turn off GPIOD0
+		GPIOD->BSHR = (1<<(16+0)) | (1<<(16+4)); // Turn off GPIOD0
 		Delay_Ms( 100 );
+		count++;
 	}
 }
diff --git a/minichlink/Makefile b/minichlink/Makefile
index bc4b278347cbcd122a33551530f02000d486e70f..d2fda917a3368e8f495886feb4e4ba81d53d5bdf 100644
--- a/minichlink/Makefile
+++ b/minichlink/Makefile
@@ -2,10 +2,10 @@ TOOLS:=minichlink
 
 all : $(TOOLS)
 
-CFLAGS:=-O1 -g
-LDFLAGS:=-lpthread -lusb-1.0
+CFLAGS:=-O0 -g3
+LDFLAGS:=-lpthread -lusb-1.0 -ludev
 
-minichlink : minichlink.c
+minichlink : minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c
 	gcc -o $@ $^ $(LDFLAGS) $(CFLAGS)
 
 install_udev_rules :
diff --git a/minichlink/hidapi.c b/minichlink/hidapi.c
new file mode 100644
index 0000000000000000000000000000000000000000..1056c56104437fa54021e88f0fd33c20c8751f4a
--- /dev/null
+++ b/minichlink/hidapi.c
@@ -0,0 +1,4475 @@
+#ifdef _WIN32
+
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+ 
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        http://github.com/signal11/hidapi .
+********************************************************/
+
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+ 
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+#include <windows.h>
+
+#ifndef _NTDEF_
+typedef LONG NTSTATUS;
+#endif
+
+#ifdef __MINGW32__
+#include <ntdef.h>
+#include <winbase.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <ntdef.h>
+#define _wcsdup wcsdup
+#endif
+
+/* The maximum number of characters that can be passed into the
+   HidD_Get*String() functions without it failing.*/
+#define MAX_STRING_WCHARS 0xFFF
+
+/*#define HIDAPI_USE_DDK*/
+
+#if defined(WINDOWS) || defined(WIN32)  || defined(WIN64) \
+                     || defined(_WIN32) || defined(_WIN64)
+#ifndef strdup
+#define strdup _strdup
+#endif
+#endif 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef TCC
+	typedef struct _SP_DEVINFO_DATA {
+		DWORD     cbSize;
+		GUID      ClassGuid;
+		DWORD     DevInst;
+		ULONG_PTR Reserved;
+	} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
+	typedef struct _SP_DEVICE_INTERFACE_DATA {
+		DWORD     cbSize;
+		GUID      InterfaceClassGuid;
+		DWORD     Flags;
+		ULONG_PTR Reserved;
+	} SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
+	typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
+		DWORD cbSize;
+		CHAR DevicePath[ANYSIZE_ARRAY];
+	} SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
+	typedef PVOID HDEVINFO;
+	
+	HDEVINFO WINAPI SetupDiGetClassDevsA(CONST GUID*,PCSTR,HWND,DWORD);
+	
+	#define DIGCF_PRESENT	0x00000002
+	#define DIGCF_DEVICEINTERFACE	0x00000010
+	#define SPDRP_CLASS	7
+	#define SPDRP_DRIVER	9
+	#define FILE_DEVICE_KEYBOARD            0x0000000b
+	#define METHOD_OUT_DIRECT                 2
+	enum
+	{ FILE_ANY_ACCESS			= 0x00000000UL,
+		FILE_SPECIAL_ACCESS			= FILE_ANY_ACCESS,
+		FILE_READ_ACCESS			= 0x00000001UL,
+		FILE_WRITE_ACCESS			= 0x00000002UL
+	};
+	#define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
+
+#define WINSETUPAPI __declspec(dllimport) //XXX Should these be CDECL?
+WINSETUPAPI BOOL SetupDiEnumDeviceInterfaces(
+  HDEVINFO                  DeviceInfoSet,
+  PSP_DEVINFO_DATA          DeviceInfoData,
+  const GUID                *InterfaceClassGuid,
+  DWORD                     MemberIndex,
+  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
+);
+WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailA(
+  HDEVINFO                           DeviceInfoSet,
+  PSP_DEVICE_INTERFACE_DATA          DeviceInterfaceData,
+  PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
+  DWORD                              DeviceInterfaceDetailDataSize,
+  PDWORD                             RequiredSize,
+  PSP_DEVINFO_DATA                   DeviceInfoData
+);
+WINSETUPAPI BOOL SetupDiEnumDeviceInfo(
+  HDEVINFO         DeviceInfoSet,
+  DWORD            MemberIndex,
+  PSP_DEVINFO_DATA DeviceInfoData
+);
+WINSETUPAPI BOOL SetupDiGetDeviceRegistryPropertyA(
+  HDEVINFO         DeviceInfoSet,
+  PSP_DEVINFO_DATA DeviceInfoData,
+  DWORD            Property,
+  PDWORD           PropertyRegDataType,
+  PBYTE            PropertyBuffer,
+  DWORD            PropertyBufferSize,
+  PDWORD           RequiredSize
+);
+WINSETUPAPI BOOL SetupDiDestroyDeviceInfoList(
+  HDEVINFO DeviceInfoSet
+);
+#else
+	#include <setupapi.h>
+	#include <winioctl.h>
+#endif
+	#ifdef HIDAPI_USE_DDK
+		#include <hidsdi.h>
+	#endif
+
+	/* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
+	#define HID_OUT_CTL_CODE(id)  \
+		CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+	#define IOCTL_HID_GET_FEATURE                   HID_OUT_CTL_CODE(100)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "hidapi.h"
+
+#undef MIN
+#define MIN(x,y) ((x) < (y)? (x): (y))
+
+#ifdef _MSC_VER
+	/* Thanks Microsoft, but I know how to use strncpy(). */
+	#pragma warning(disable:4996)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HIDAPI_USE_DDK
+	/* Since we're not building with the DDK, and the HID header
+	   files aren't part of the SDK, we have to define all this
+	   stuff here. In lookup_functions(), the function pointers
+	   defined below are set. */
+	typedef struct _HIDD_ATTRIBUTES{
+		ULONG Size;
+		USHORT VendorID;
+		USHORT ProductID;
+		USHORT VersionNumber;
+	} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+	typedef USHORT USAGE;
+	typedef struct _HIDP_CAPS {
+		USAGE Usage;
+		USAGE UsagePage;
+		USHORT InputReportByteLength;
+		USHORT OutputReportByteLength;
+		USHORT FeatureReportByteLength;
+		USHORT Reserved[17];
+		USHORT fields_not_used_by_hidapi[10];
+	} HIDP_CAPS, *PHIDP_CAPS;
+	typedef void* PHIDP_PREPARSED_DATA;
+	#define HIDP_STATUS_SUCCESS 0x110000
+
+	typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
+	typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
+	typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+	typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+	typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
+	typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
+	typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
+	typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
+	typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
+	typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
+	typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
+
+	static HidD_GetAttributes_ HidD_GetAttributes;
+	static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
+	static HidD_GetManufacturerString_ HidD_GetManufacturerString;
+	static HidD_GetProductString_ HidD_GetProductString;
+	static HidD_SetFeature_ HidD_SetFeature;
+	static HidD_GetFeature_ HidD_GetFeature;
+	static HidD_GetIndexedString_ HidD_GetIndexedString;
+	static HidD_GetPreparsedData_ HidD_GetPreparsedData;
+	static HidD_FreePreparsedData_ HidD_FreePreparsedData;
+	static HidP_GetCaps_ HidP_GetCaps;
+	static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
+
+	static HMODULE lib_handle = NULL;
+	static BOOLEAN initialized = FALSE;
+#endif /* HIDAPI_USE_DDK */
+
+struct hid_device_ {
+		HANDLE device_handle;
+		BOOL blocking;
+		USHORT output_report_length;
+		size_t input_report_length;
+		void *last_error_str;
+		DWORD last_error_num;
+		BOOL read_pending;
+		char *read_buf;
+		OVERLAPPED ol;
+};
+
+static hid_device *new_hid_device()
+{
+	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+	dev->device_handle = INVALID_HANDLE_VALUE;
+	dev->blocking = TRUE;
+	dev->output_report_length = 0;
+	dev->input_report_length = 0;
+	dev->last_error_str = NULL;
+	dev->last_error_num = 0;
+	dev->read_pending = FALSE;
+	dev->read_buf = NULL;
+	memset(&dev->ol, 0, sizeof(dev->ol));
+	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
+
+	return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+	CloseHandle(dev->ol.hEvent);
+	CloseHandle(dev->device_handle);
+	LocalFree(dev->last_error_str);
+	free(dev->read_buf);
+	free(dev);
+}
+
+static void register_error(hid_device *device, const char *op)
+{
+	WCHAR *ptr, *msg;
+
+	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+		FORMAT_MESSAGE_FROM_SYSTEM |
+		FORMAT_MESSAGE_IGNORE_INSERTS,
+		NULL,
+		GetLastError(),
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPVOID)&msg, 0/*sz*/,
+		NULL);
+	
+	/* Get rid of the CR and LF that FormatMessage() sticks at the
+	   end of the message. Thanks Microsoft! */
+	ptr = msg;
+	while (*ptr) {
+		if (*ptr == '\r') {
+			*ptr = 0x0000;
+			break;
+		}
+		ptr++;
+	}
+
+	/* Store the message off in the Device entry so that
+	   the hid_error() function can pick it up. */
+	LocalFree(device->last_error_str);
+	device->last_error_str = msg;
+}
+
+#ifndef HIDAPI_USE_DDK
+static int lookup_functions()
+{
+	lib_handle = LoadLibraryA("hid.dll");
+	if (lib_handle) {
+#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
+		RESOLVE(HidD_GetAttributes);
+		RESOLVE(HidD_GetSerialNumberString);
+		RESOLVE(HidD_GetManufacturerString);
+		RESOLVE(HidD_GetProductString);
+		RESOLVE(HidD_SetFeature);
+		RESOLVE(HidD_GetFeature);
+		RESOLVE(HidD_GetIndexedString);
+		RESOLVE(HidD_GetPreparsedData);
+		RESOLVE(HidD_FreePreparsedData);
+		RESOLVE(HidP_GetCaps);
+		RESOLVE(HidD_SetNumInputBuffers);
+#undef RESOLVE
+	}
+	else
+		return -1;
+
+	return 0;
+}
+#endif
+
+static HANDLE open_device(const char *path, BOOL enumerate)
+{
+	HANDLE handle;
+	DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
+	DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+
+	handle = CreateFileA(path,
+		desired_access,
+		share_mode,
+		NULL,
+		OPEN_EXISTING,
+		FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
+		0);
+
+	return handle;
+}
+
+int HID_API_EXPORT hid_init(void)
+{
+#ifndef HIDAPI_USE_DDK
+	if (!initialized) {
+		if (lookup_functions() < 0) {
+			hid_exit();
+			return -1;
+		}
+		initialized = TRUE;
+	}
+#endif
+	return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+#ifndef HIDAPI_USE_DDK
+	if (lib_handle)
+		FreeLibrary(lib_handle);
+	lib_handle = NULL;
+	initialized = FALSE;
+#endif
+	return 0;
+}
+
+struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+	BOOL res;
+	struct hid_device_info *root = NULL; /* return object */
+	struct hid_device_info *cur_dev = NULL;
+
+	/* Windows objects for interacting with the driver. */
+	GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
+	SP_DEVINFO_DATA devinfo_data;
+	SP_DEVICE_INTERFACE_DATA device_interface_data;
+	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
+	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
+	int device_index = 0;
+	int i;
+
+	if (hid_init() < 0)
+		return NULL;
+
+	/* Initialize the Windows objects. */
+	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
+	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
+	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+	/* Get information for all the devices belonging to the HID class. */
+	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+	
+	/* Iterate over each device in the HID class, looking for the right one. */
+	
+	for (;;) {
+		HANDLE write_handle = INVALID_HANDLE_VALUE;
+		DWORD required_size = 0;
+		HIDD_ATTRIBUTES attrib;
+
+		res = SetupDiEnumDeviceInterfaces(device_info_set,
+			NULL,
+			&InterfaceClassGuid,
+			device_index,
+			&device_interface_data);
+		
+		if (!res) {
+			/* A return of FALSE from this function means that
+			   there are no more devices. */
+			break;
+		}
+
+		/* Call with 0-sized detail size, and let the function
+		   tell us how long the detail struct needs to be. The
+		   size is put in &required_size. */
+		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+			&device_interface_data,
+			NULL,
+			0,
+			&required_size,
+			NULL);
+
+		/* Allocate a long enough structure for device_interface_detail_data. */
+		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
+		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+
+		/* Get the detailed data for this device. The detail data gives us
+		   the device path for this device, which is then passed into
+		   CreateFile() to get a handle to the device. */
+		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+			&device_interface_data,
+			device_interface_detail_data,
+			required_size,
+			NULL,
+			NULL);
+
+		if (!res) {
+			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
+			   Continue to the next device. */
+			goto cont;
+		}
+
+		/* Make sure this device is of Setup Class "HIDClass" and has a
+		   driver bound to it. */
+		for (i = 0; ; i++) {
+			char driver_name[256];
+
+			/* Populate devinfo_data. This function will return failure
+			   when there are no more interfaces left. */
+			res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+			if (!res)
+				goto cont;
+
+			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+			if (!res)
+				goto cont;
+
+			if (strcmp(driver_name, "HIDClass") == 0) {
+				/* See if there's a driver bound. */
+				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+				if (res)
+					break;
+			}
+		}
+
+		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
+
+		/* Open a handle to the device */
+		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);
+
+		/* Check validity of write_handle. */
+		if (write_handle == INVALID_HANDLE_VALUE) {
+			/* Unable to open the device. */
+			//register_error(dev, "CreateFile");
+			goto cont_close;
+		}		
+
+
+		/* Get the Vendor ID and Product ID for this device. */
+		attrib.Size = sizeof(HIDD_ATTRIBUTES);
+		HidD_GetAttributes(write_handle, &attrib);
+		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
+
+		/* Check the VID/PID to see if we should add this
+		   device to the enumeration list. */
+		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
+		    (product_id == 0x0 || attrib.ProductID == product_id)) {
+
+			#define WSTR_LEN 512
+			const char *str;
+			struct hid_device_info *tmp;
+			PHIDP_PREPARSED_DATA pp_data = NULL;
+			HIDP_CAPS caps;
+			BOOLEAN res;
+			NTSTATUS nt_res;
+			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
+			size_t len;
+
+			/* VID/PID match. Create the record. */
+			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+			if (cur_dev) {
+				cur_dev->next = tmp;
+			}
+			else {
+				root = tmp;
+			}
+			cur_dev = tmp;
+
+			/* Get the Usage Page and Usage for this device. */
+			res = HidD_GetPreparsedData(write_handle, &pp_data);
+			if (res) {
+				nt_res = HidP_GetCaps(pp_data, &caps);
+				if (nt_res == HIDP_STATUS_SUCCESS) {
+					cur_dev->usage_page = caps.UsagePage;
+					cur_dev->usage = caps.Usage;
+				}
+
+				HidD_FreePreparsedData(pp_data);
+			}
+			
+			/* Fill out the record */
+			cur_dev->next = NULL;
+			str = device_interface_detail_data->DevicePath;
+			if (str) {
+				len = strlen(str);
+				cur_dev->path = (char*) calloc(len+1, sizeof(char));
+				strncpy(cur_dev->path, str, len+1);
+				cur_dev->path[len] = '\0';
+			}
+			else
+				cur_dev->path = NULL;
+
+			/* Serial Number */
+			res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
+			wstr[WSTR_LEN-1] = 0x0000;
+			if (res) {
+				cur_dev->serial_number = _wcsdup(wstr);
+			}
+
+			/* Manufacturer String */
+			res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
+			wstr[WSTR_LEN-1] = 0x0000;
+			if (res) {
+				cur_dev->manufacturer_string = _wcsdup(wstr);
+			}
+
+			/* Product String */
+			res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
+			wstr[WSTR_LEN-1] = 0x0000;
+			if (res) {
+				cur_dev->product_string = _wcsdup(wstr);
+			}
+
+			/* VID/PID */
+			cur_dev->vendor_id = attrib.VendorID;
+			cur_dev->product_id = attrib.ProductID;
+
+			/* Release Number */
+			cur_dev->release_number = attrib.VersionNumber;
+
+			/* Interface Number. It can sometimes be parsed out of the path
+			   on Windows if a device has multiple interfaces. See
+			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
+			   search for "Hardware IDs for HID Devices" at MSDN. If it's not
+			   in the path, it's set to -1. */
+			cur_dev->interface_number = -1;
+			if (cur_dev->path) {
+				char *interface_component = strstr(cur_dev->path, "&mi_");
+				if (interface_component) {
+					char *hex_str = interface_component + 4;
+					char *endptr = NULL;
+					cur_dev->interface_number = strtol(hex_str, &endptr, 16);
+					if (endptr == hex_str) {
+						/* The parsing failed. Set interface_number to -1. */
+						cur_dev->interface_number = -1;
+					}
+				}
+			}
+		}
+
+cont_close:
+		CloseHandle(write_handle);
+cont:
+		/* We no longer need the detail data. It can be freed */
+		free(device_interface_detail_data);
+
+		device_index++;
+
+	}
+
+	/* Close the device information handle. */
+	SetupDiDestroyDeviceInfoList(device_info_set);
+
+	return root;
+
+}
+
+void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
+{
+	/* TODO: Merge this with the Linux version. This function is platform-independent. */
+	struct hid_device_info *d = devs;
+	while (d) {
+		struct hid_device_info *next = d->next;
+		free(d->path);
+		free(d->serial_number);
+		free(d->manufacturer_string);
+		free(d->product_string);
+		free(d);
+		d = next;
+	}
+}
+
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
+	struct hid_device_info *devs, *cur_dev;
+	const char *path_to_open = NULL;
+	hid_device *handle = NULL;
+	
+	devs = hid_enumerate(vendor_id, product_id);
+	cur_dev = devs;
+	while (cur_dev) {
+		if (cur_dev->vendor_id == vendor_id &&
+		    cur_dev->product_id == product_id) {
+			if (serial_number) {
+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+					path_to_open = cur_dev->path;
+					break;
+				}
+			}
+			else {
+				path_to_open = cur_dev->path;
+				break;
+			}
+		}
+		cur_dev = cur_dev->next;
+	}
+
+	if (path_to_open) {
+		/* Open the device */
+		handle = hid_open_path(path_to_open);
+	}
+
+	hid_free_enumeration(devs);
+	
+	return handle;
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
+{
+	hid_device *dev;
+	HIDP_CAPS caps;
+	PHIDP_PREPARSED_DATA pp_data = NULL;
+	BOOLEAN res;
+	NTSTATUS nt_res;
+
+	if (hid_init() < 0) {
+		return NULL;
+	}
+
+	dev = new_hid_device();
+
+	/* Open a handle to the device */
+	dev->device_handle = open_device(path, FALSE);
+
+	/* Check validity of write_handle. */
+	if (dev->device_handle == INVALID_HANDLE_VALUE) {
+		/* Unable to open the device. */
+		register_error(dev, "CreateFile");
+		goto err;
+	}
+
+	/* Set the Input Report buffer size to 64 reports. */
+	res = HidD_SetNumInputBuffers(dev->device_handle, 64);
+	if (!res) {
+		register_error(dev, "HidD_SetNumInputBuffers");
+		goto err;
+	}
+
+	/* Get the Input Report length for the device. */
+	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
+	if (!res) {
+		register_error(dev, "HidD_GetPreparsedData");
+		goto err;
+	}
+	nt_res = HidP_GetCaps(pp_data, &caps);
+	if (nt_res != HIDP_STATUS_SUCCESS) {
+		register_error(dev, "HidP_GetCaps");	
+		goto err_pp_data;
+	}
+	dev->output_report_length = caps.OutputReportByteLength;
+	dev->input_report_length = caps.InputReportByteLength;
+	HidD_FreePreparsedData(pp_data);
+
+	dev->read_buf = (char*) malloc(dev->input_report_length);
+
+	return dev;
+
+err_pp_data:
+		HidD_FreePreparsedData(pp_data);
+err:	
+		free_hid_device(dev);
+		return NULL;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+	DWORD bytes_written;
+	BOOL res;
+
+	OVERLAPPED ol;
+	unsigned char *buf;
+	memset(&ol, 0, sizeof(ol));
+
+	/* Make sure the right number of bytes are passed to WriteFile. Windows
+	   expects the number of bytes which are in the _longest_ report (plus
+	   one for the report number) bytes even if the data is a report
+	   which is shorter than that. Windows gives us this value in
+	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,
+	   create a temporary buffer which is the proper size. */
+	if (length >= dev->output_report_length) {
+		/* The user passed the right number of bytes. Use the buffer as-is. */
+		buf = (unsigned char *) data;
+	} else {
+		/* Create a temporary buffer and copy the user's data
+		   into it, padding the rest with zeros. */
+		buf = (unsigned char *) malloc(dev->output_report_length);
+		memcpy(buf, data, length);
+		memset(buf + length, 0, dev->output_report_length - length);
+		length = dev->output_report_length;
+	}
+
+	res = WriteFile(dev->device_handle, buf, (DWORD)length, NULL, &ol);
+	int err = GetLastError();
+	
+	if (!res) {
+		if (err != ERROR_IO_PENDING) {
+			/* WriteFile() failed. Return error. */
+			register_error(dev, "WriteFile");
+			bytes_written = -1;
+			goto end_of_function;
+		}
+	}
+
+	/* Wait here until the write is done. This makes
+	   hid_write() synchronous. */
+	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
+	if (!res) {
+		/* The Write operation failed. */
+		register_error(dev, "WriteFile");
+		bytes_written = -1;
+		goto end_of_function;
+	}
+
+end_of_function:
+	if (buf != data)
+		free(buf);
+
+	return bytes_written;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+	DWORD bytes_read = 0;
+	size_t copy_len = 0;
+	BOOL res;
+
+	/* Copy the handle for convenience. */
+	HANDLE ev = dev->ol.hEvent;
+
+	if (!dev->read_pending) {
+		/* Start an Overlapped I/O read. */
+		dev->read_pending = TRUE;
+		memset(dev->read_buf, 0, dev->input_report_length);
+		ResetEvent(ev);
+		res = ReadFile(dev->device_handle, dev->read_buf, (DWORD)dev->input_report_length, &bytes_read, &dev->ol);
+		
+		if (!res) {
+			if (GetLastError() != ERROR_IO_PENDING) {
+				/* ReadFile() has failed.
+				   Clean up and return error. */
+				CancelIo(dev->device_handle);
+				dev->read_pending = FALSE;
+				goto end_of_function;
+			}
+		}
+	}
+
+	if (milliseconds >= 0) {
+		/* See if there is any data yet. */
+		res = WaitForSingleObject(ev, milliseconds);
+		if (res != WAIT_OBJECT_0) {
+			/* There was no data this time. Return zero bytes available,
+			   but leave the Overlapped I/O running. */
+			return 0;
+		}
+	}
+
+	/* Either WaitForSingleObject() told us that ReadFile has completed, or
+	   we are in non-blocking mode. Get the number of bytes read. The actual
+	   data has been copied to the data[] array which was passed to ReadFile(). */
+	res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
+	
+	/* Set pending back to false, even if GetOverlappedResult() returned error. */
+	dev->read_pending = FALSE;
+
+	if (res && bytes_read > 0) {
+		if (dev->read_buf[0] == 0x0) {
+			/* If report numbers aren't being used, but Windows sticks a report
+			   number (0x0) on the beginning of the report anyway. To make this
+			   work like the other platforms, and to make it work more like the
+			   HID spec, we'll skip over this byte. */
+			bytes_read--;
+			copy_len = length > bytes_read ? bytes_read : length;
+			memcpy(data, dev->read_buf+1, copy_len);
+		}
+		else {
+			/* Copy the whole buffer, report number and all. */
+			copy_len = length > bytes_read ? bytes_read : length;
+			memcpy(data, dev->read_buf, copy_len);
+		}
+	}
+	
+end_of_function:
+	if (!res) {
+		register_error(dev, "GetOverlappedResult");
+		return -1;
+	}
+	
+	return (int)copy_len;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+	dev->blocking = !nonblock;
+	return 0; /* Success */
+}
+
+int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+	BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
+	if (!res) {
+		register_error(dev, "HidD_SetFeature");
+		return -1;
+	}
+
+	return (int)length;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	BOOL res;
+#if 0
+	res = HidD_GetFeature(dev->device_handle, data, length);
+	if (!res) {
+		register_error(dev, "HidD_GetFeature");
+		return -1;
+	}
+	return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
+#else
+	DWORD bytes_returned;
+
+	OVERLAPPED ol;
+	memset(&ol, 0, sizeof(ol));
+
+	res = DeviceIoControl(dev->device_handle,
+		IOCTL_HID_GET_FEATURE,
+		data, (DWORD)length,
+		data, (DWORD)length,
+		&bytes_returned, &ol);
+
+	if (!res) {
+		if (GetLastError() != ERROR_IO_PENDING) {
+			/* DeviceIoControl() failed. Return error. */
+			register_error(dev, "Send Feature Report DeviceIoControl");
+			return -1;
+		}
+	}
+
+	/* Wait here until the write is done. This makes
+	   hid_get_feature_report() synchronous. */
+	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
+	if (!res) {
+		/* The operation failed. */
+		register_error(dev, "Send Feature Report GetOverLappedResult");
+		return -1;
+	}
+
+	/* bytes_returned does not include the first byte which contains the
+	   report ID. The data buffer actually contains one more byte than
+	   bytes_returned. */
+	bytes_returned++;
+
+	return bytes_returned;
+#endif
+}
+
+void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
+{
+	if (!dev)
+		return;
+	CancelIo(dev->device_handle);
+	free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	BOOL res;
+
+	res = HidD_GetManufacturerString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+	if (!res) {
+		register_error(dev, "HidD_GetManufacturerString");
+		return -1;
+	}
+
+	return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	BOOL res;
+
+	res = HidD_GetProductString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+	if (!res) {
+		register_error(dev, "HidD_GetProductString");
+		return -1;
+	}
+
+	return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	BOOL res;
+
+	res = HidD_GetSerialNumberString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+	if (!res) {
+		register_error(dev, "HidD_GetSerialNumberString");
+		return -1;
+	}
+
+	return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+	BOOL res;
+
+	res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+	if (!res) {
+		register_error(dev, "HidD_GetIndexedString");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+	return (wchar_t*)dev->last_error_str;
+}
+
+
+/*#define PICPGM*/
+/*#define S11*/
+#define P32
+#ifdef S11 
+  unsigned short VendorID = 0xa0a0;
+	unsigned short ProductID = 0x0001;
+#endif
+
+#ifdef P32
+  unsigned short VendorID = 0x04d8;
+	unsigned short ProductID = 0x3f;
+#endif
+
+
+#ifdef PICPGM
+  unsigned short VendorID = 0x04d8;
+  unsigned short ProductID = 0x0033;
+#endif
+
+
+#if 0
+int __cdecl main(int argc, char* argv[])
+{
+	int res;
+	unsigned char buf[65];
+
+	UNREFERENCED_PARAMETER(argc);
+	UNREFERENCED_PARAMETER(argv);
+
+	/* Set up the command buffer. */
+	memset(buf,0x00,sizeof(buf));
+	buf[0] = 0;
+	buf[1] = 0x81;
+	
+
+	/* Open the device. */
+	int handle = open(VendorID, ProductID, L"12345");
+	if (handle < 0)
+		printf("unable to open device\n");
+
+
+	/* Toggle LED (cmd 0x80) */
+	buf[1] = 0x80;
+	res = write(handle, buf, 65);
+	if (res < 0)
+		printf("Unable to write()\n");
+
+	/* Request state (cmd 0x81) */
+	buf[1] = 0x81;
+	write(handle, buf, 65);
+	if (res < 0)
+		printf("Unable to write() (2)\n");
+
+	/* Read requested state */
+	read(handle, buf, 65);
+	if (res < 0)
+		printf("Unable to read()\n");
+
+	/* Print out the returned buffer. */
+	for (int i = 0; i < 4; i++)
+		printf("buf[%d]: %d\n", i, buf[i]);
+
+	return 0;
+}
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#elif defined( __MACOSX__ )
+
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 2010-07-03
+
+ Copyright 2010, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        http://github.com/signal11/hidapi .
+********************************************************/
+
+/* See Apple Technical Note TN2187 for details on IOHidManager. */
+
+#include <IOKit/hid/IOHIDManager.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/IOKitLib.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <wchar.h>
+#include <locale.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include "hidapi.h"
+
+/* Barrier implementation because Mac OSX doesn't have pthread_barrier.
+   It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
+   This implementation came from Brent Priddy and was posted on
+   StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int count;
+    int trip_count;
+} pthread_barrier_t;
+
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
+{
+	if(count == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+		return -1;
+	}
+	if(pthread_cond_init(&barrier->cond, 0) < 0) {
+		pthread_mutex_destroy(&barrier->mutex);
+		return -1;
+	}
+	barrier->trip_count = count;
+	barrier->count = 0;
+
+	return 0;
+}
+
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+	pthread_cond_destroy(&barrier->cond);
+	pthread_mutex_destroy(&barrier->mutex);
+	return 0;
+}
+
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+	pthread_mutex_lock(&barrier->mutex);
+	++(barrier->count);
+	if(barrier->count >= barrier->trip_count)
+	{
+		barrier->count = 0;
+		pthread_cond_broadcast(&barrier->cond);
+		pthread_mutex_unlock(&barrier->mutex);
+		return 1;
+	}
+	else
+	{
+		pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+		pthread_mutex_unlock(&barrier->mutex);
+		return 0;
+	}
+}
+
+static int return_data(hid_device *dev, unsigned char *data, size_t length);
+
+/* Linked List of input reports received from the device. */
+struct input_report {
+	uint8_t *data;
+	size_t len;
+	struct input_report *next;
+};
+
+struct hid_device_ {
+	IOHIDDeviceRef device_handle;
+	int blocking;
+	int uses_numbered_reports;
+	int disconnected;
+	CFStringRef run_loop_mode;
+	CFRunLoopRef run_loop;
+	CFRunLoopSourceRef source;
+	uint8_t *input_report_buf;
+	CFIndex max_input_report_len;
+	struct input_report *input_reports;
+
+	pthread_t thread;
+	pthread_mutex_t mutex; /* Protects input_reports */
+	pthread_cond_t condition;
+	pthread_barrier_t barrier; /* Ensures correct startup sequence */
+	pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
+	int shutdown_thread;
+};
+
+static hid_device *new_hid_device(void)
+{
+	hid_device *dev = calloc(1, sizeof(hid_device));
+	dev->device_handle = NULL;
+	dev->blocking = 1;
+	dev->uses_numbered_reports = 0;
+	dev->disconnected = 0;
+	dev->run_loop_mode = NULL;
+	dev->run_loop = NULL;
+	dev->source = NULL;
+	dev->input_report_buf = NULL;
+	dev->input_reports = NULL;
+	dev->shutdown_thread = 0;
+
+	/* Thread objects */
+	pthread_mutex_init(&dev->mutex, NULL);
+	pthread_cond_init(&dev->condition, NULL);
+	pthread_barrier_init(&dev->barrier, NULL, 2);
+	pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);
+
+	return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+	if (!dev)
+		return;
+
+	/* Delete any input reports still left over. */
+	struct input_report *rpt = dev->input_reports;
+	while (rpt) {
+		struct input_report *next = rpt->next;
+		free(rpt->data);
+		free(rpt);
+		rpt = next;
+	}
+
+	/* Free the string and the report buffer. The check for NULL
+	   is necessary here as CFRelease() doesn't handle NULL like
+	   free() and others do. */
+	if (dev->run_loop_mode)
+		CFRelease(dev->run_loop_mode);
+	if (dev->source)
+		CFRelease(dev->source);
+	free(dev->input_report_buf);
+
+	/* Clean up the thread objects */
+	pthread_barrier_destroy(&dev->shutdown_barrier);
+	pthread_barrier_destroy(&dev->barrier);
+	pthread_cond_destroy(&dev->condition);
+	pthread_mutex_destroy(&dev->mutex);
+
+	/* Free the structure itself. */
+	free(dev);
+}
+
+static	IOHIDManagerRef hid_mgr = 0x0;
+
+
+#if 0
+static void register_error(hid_device *device, const char *op)
+{
+
+}
+#endif
+
+
+static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)
+{
+	CFTypeRef ref;
+	int32_t value;
+
+	ref = IOHIDDeviceGetProperty(device, key);
+	if (ref) {
+		if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
+			CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);
+			return value;
+		}
+	}
+	return 0;
+}
+
+static unsigned short get_vendor_id(IOHIDDeviceRef device)
+{
+	return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
+}
+
+static unsigned short get_product_id(IOHIDDeviceRef device)
+{
+	return get_int_property(device, CFSTR(kIOHIDProductIDKey));
+}
+
+static int32_t get_max_report_length(IOHIDDeviceRef device)
+{
+	return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
+}
+
+static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)
+{
+	CFStringRef str;
+
+	if (!len)
+		return 0;
+
+	str = IOHIDDeviceGetProperty(device, prop);
+
+	buf[0] = 0;
+
+	if (str) {
+		CFIndex str_len = CFStringGetLength(str);
+		CFRange range;
+		CFIndex used_buf_len;
+		CFIndex chars_copied;
+
+		len --;
+
+		range.location = 0;
+		range.length = ((size_t)str_len > len)? len: (size_t)str_len;
+		chars_copied = CFStringGetBytes(str,
+			range,
+			kCFStringEncodingUTF32LE,
+			(char)'?',
+			FALSE,
+			(UInt8*)buf,
+			len * sizeof(wchar_t),
+			&used_buf_len);
+
+		if (chars_copied == len)
+			buf[len] = 0; /* len is decremented above */
+		else
+			buf[chars_copied] = 0;
+
+		return 0;
+	}
+	else
+		return -1;
+
+}
+
+static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+	return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
+}
+
+static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+	return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);
+}
+
+static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+	return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);
+}
+
+
+/* Implementation of wcsdup() for Mac. */
+static wchar_t *dup_wcs(const wchar_t *s)
+{
+	size_t len = wcslen(s);
+	wchar_t *ret = malloc((len+1)*sizeof(wchar_t));
+	wcscpy(ret, s);
+
+	return ret;
+}
+
+/* hidapi_IOHIDDeviceGetService()
+ *
+ * Return the io_service_t corresponding to a given IOHIDDeviceRef, either by:
+ * - on OS X 10.6 and above, calling IOHIDDeviceGetService()
+ * - on OS X 10.5, extract it from the IOHIDDevice struct
+ */
+static io_service_t hidapi_IOHIDDeviceGetService(IOHIDDeviceRef device)
+{
+	static void *iokit_framework = NULL;
+	static io_service_t (*dynamic_IOHIDDeviceGetService)(IOHIDDeviceRef device) = NULL;
+
+	/* Use dlopen()/dlsym() to get a pointer to IOHIDDeviceGetService() if it exists.
+	 * If any of these steps fail, dynamic_IOHIDDeviceGetService will be left NULL
+	 * and the fallback method will be used.
+	 */
+	if (iokit_framework == NULL) {
+		iokit_framework = dlopen("/System/Library/IOKit.framework/IOKit", RTLD_LAZY);
+
+		if (iokit_framework != NULL)
+			dynamic_IOHIDDeviceGetService = dlsym(iokit_framework, "IOHIDDeviceGetService");
+	}
+
+	if (dynamic_IOHIDDeviceGetService != NULL) {
+		/* Running on OS X 10.6 and above: IOHIDDeviceGetService() exists */
+		return dynamic_IOHIDDeviceGetService(device);
+	}
+	else
+	{
+		/* Running on OS X 10.5: IOHIDDeviceGetService() doesn't exist.
+		 *
+		 * Be naughty and pull the service out of the IOHIDDevice.
+		 * IOHIDDevice is an opaque struct not exposed to applications, but its
+		 * layout is stable through all available versions of OS X.
+		 * Tested and working on OS X 10.5.8 i386, x86_64, and ppc.
+		 */
+		struct IOHIDDevice_internal {
+			/* The first field of the IOHIDDevice struct is a
+			 * CFRuntimeBase (which is a private CF struct).
+			 *
+			 * a, b, and c are the 3 fields that make up a CFRuntimeBase.
+			 * See http://opensource.apple.com/source/CF/CF-476.18/CFRuntime.h
+			 *
+			 * The second field of the IOHIDDevice is the io_service_t we're looking for.
+			 */
+			uintptr_t a;
+			uint8_t b[4];
+#if __LP64__
+			uint32_t c;
+#endif
+			io_service_t service;
+		};
+		struct IOHIDDevice_internal *tmp = (struct IOHIDDevice_internal *)device;
+
+		return tmp->service;
+	}
+}
+
+/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
+static int init_hid_manager(void)
+{
+	/* Initialize all the HID Manager Objects */
+	hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+	if (hid_mgr) {
+		IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+		IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+		return 0;
+	}
+
+	return -1;
+}
+
+/* Initialize the IOHIDManager if necessary. This is the public function, and
+   it is safe to call this function repeatedly. Return 0 for success and -1
+   for failure. */
+int HID_API_EXPORT hid_init(void)
+{
+	if (!hid_mgr) {
+		return init_hid_manager();
+	}
+
+	/* Already initialized. */
+	return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+	if (hid_mgr) {
+		/* Close the HID manager. */
+		IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
+		CFRelease(hid_mgr);
+		hid_mgr = NULL;
+	}
+
+	return 0;
+}
+
+static void process_pending_events(void) {
+	SInt32 res;
+	do {
+		res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);
+	} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
+}
+
+struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+	struct hid_device_info *root = NULL; /* return object */
+	struct hid_device_info *cur_dev = NULL;
+	CFIndex num_devices;
+	int i;
+
+	/* Set up the HID Manager if it hasn't been done */
+	if (hid_init() < 0)
+		return NULL;
+
+	/* give the IOHIDManager a chance to update itself */
+	process_pending_events();
+
+	/* Get a list of the Devices */
+	IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
+
+	/* Convert the list into a C array so we can iterate easily. */
+	num_devices = CFSetGetCount(device_set);
+	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
+	CFSetGetValues(device_set, (const void **) device_array);
+
+	/* Iterate over each device, making an entry for it. */
+	for (i = 0; i < num_devices; i++) {
+		unsigned short dev_vid;
+		unsigned short dev_pid;
+		#define BUF_LEN 256
+		wchar_t buf[BUF_LEN];
+
+		IOHIDDeviceRef dev = device_array[i];
+
+        if (!dev) {
+            continue;
+        }
+		dev_vid = get_vendor_id(dev);
+		dev_pid = get_product_id(dev);
+
+		/* Check the VID/PID against the arguments */
+		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+		    (product_id == 0x0 || product_id == dev_pid)) {
+			struct hid_device_info *tmp;
+			io_object_t iokit_dev;
+			kern_return_t res;
+			io_string_t path;
+
+			/* VID/PID match. Create the record. */
+			tmp = malloc(sizeof(struct hid_device_info));
+			if (cur_dev) {
+				cur_dev->next = tmp;
+			}
+			else {
+				root = tmp;
+			}
+			cur_dev = tmp;
+
+			/* Get the Usage Page and Usage for this device. */
+			cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
+			cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
+
+			/* Fill out the record */
+			cur_dev->next = NULL;
+
+			/* Fill in the path (IOService plane) */
+			iokit_dev = hidapi_IOHIDDeviceGetService(dev);
+			res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path);
+			if (res == KERN_SUCCESS)
+				cur_dev->path = strdup(path);
+			else
+				cur_dev->path = strdup("");
+
+			/* Serial Number */
+			get_serial_number(dev, buf, BUF_LEN);
+			cur_dev->serial_number = dup_wcs(buf);
+
+			/* Manufacturer and Product strings */
+			get_manufacturer_string(dev, buf, BUF_LEN);
+			cur_dev->manufacturer_string = dup_wcs(buf);
+			get_product_string(dev, buf, BUF_LEN);
+			cur_dev->product_string = dup_wcs(buf);
+
+			/* VID/PID */
+			cur_dev->vendor_id = dev_vid;
+			cur_dev->product_id = dev_pid;
+
+			/* Release Number */
+			cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
+
+			/* Interface Number (Unsupported on Mac)*/
+			cur_dev->interface_number = -1;
+		}
+	}
+
+	free(device_array);
+	CFRelease(device_set);
+
+	return root;
+}
+
+void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+	/* This function is identical to the Linux version. Platform independent. */
+	struct hid_device_info *d = devs;
+	while (d) {
+		struct hid_device_info *next = d->next;
+		free(d->path);
+		free(d->serial_number);
+		free(d->manufacturer_string);
+		free(d->product_string);
+		free(d);
+		d = next;
+	}
+}
+
+hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+	/* This function is identical to the Linux version. Platform independent. */
+	struct hid_device_info *devs, *cur_dev;
+	const char *path_to_open = NULL;
+	hid_device * handle = NULL;
+
+	devs = hid_enumerate(vendor_id, product_id);
+	cur_dev = devs;
+	while (cur_dev) {
+		if (cur_dev->vendor_id == vendor_id &&
+		    cur_dev->product_id == product_id) {
+			if (serial_number) {
+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+					path_to_open = cur_dev->path;
+					break;
+				}
+			}
+			else {
+				path_to_open = cur_dev->path;
+				break;
+			}
+		}
+		cur_dev = cur_dev->next;
+	}
+
+	if (path_to_open) {
+		/* Open the device */
+		handle = hid_open_path(path_to_open);
+	}
+
+	hid_free_enumeration(devs);
+
+	return handle;
+}
+
+static void hid_device_removal_callback(void *context, IOReturn result,
+                                        void *sender)
+{
+	/* Stop the Run Loop for this device. */
+	hid_device *d = context;
+
+	d->disconnected = 1;
+	CFRunLoopStop(d->run_loop);
+}
+
+/* The Run Loop calls this function for each input report received.
+   This function puts the data into a linked list to be picked up by
+   hid_read(). */
+static void hid_report_callback(void *context, IOReturn result, void *sender,
+                         IOHIDReportType report_type, uint32_t report_id,
+                         uint8_t *report, CFIndex report_length)
+{
+	struct input_report *rpt;
+	hid_device *dev = context;
+
+	/* Make a new Input Report object */
+	rpt = calloc(1, sizeof(struct input_report));
+	rpt->data = calloc(1, report_length);
+	memcpy(rpt->data, report, report_length);
+	rpt->len = report_length;
+	rpt->next = NULL;
+
+	/* Lock this section */
+	pthread_mutex_lock(&dev->mutex);
+
+	/* Attach the new report object to the end of the list. */
+	if (dev->input_reports == NULL) {
+		/* The list is empty. Put it at the root. */
+		dev->input_reports = rpt;
+	}
+	else {
+		/* Find the end of the list and attach. */
+		struct input_report *cur = dev->input_reports;
+		int num_queued = 0;
+		while (cur->next != NULL) {
+			cur = cur->next;
+			num_queued++;
+		}
+		cur->next = rpt;
+
+		/* Pop one off if we've reached 30 in the queue. This
+		   way we don't grow forever if the user never reads
+		   anything from the device. */
+		if (num_queued > 30) {
+			return_data(dev, NULL, 0);
+		}
+	}
+
+	/* Signal a waiting thread that there is data. */
+	pthread_cond_signal(&dev->condition);
+
+	/* Unlock */
+	pthread_mutex_unlock(&dev->mutex);
+
+}
+
+/* This gets called when the read_thread's run loop gets signaled by
+   hid_close(), and serves to stop the read_thread's run loop. */
+static void perform_signal_callback(void *context)
+{
+	hid_device *dev = context;
+	CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/
+}
+
+static void *read_thread(void *param)
+{
+	hid_device *dev = param;
+	SInt32 code;
+
+	/* Move the device's run loop to this thread. */
+	IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
+
+	/* Create the RunLoopSource which is used to signal the
+	   event loop to stop when hid_close() is called. */
+	CFRunLoopSourceContext ctx;
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.version = 0;
+	ctx.info = dev;
+	ctx.perform = &perform_signal_callback;
+	dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
+	CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
+
+	/* Store off the Run Loop so it can be stopped from hid_close()
+	   and on device disconnection. */
+	dev->run_loop = CFRunLoopGetCurrent();
+
+	/* Notify the main thread that the read thread is up and running. */
+	pthread_barrier_wait(&dev->barrier);
+
+	/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
+	   reports into the hid_report_callback(). */
+	while (!dev->shutdown_thread && !dev->disconnected) {
+		code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
+		/* Return if the device has been disconnected */
+		if (code == kCFRunLoopRunFinished) {
+			dev->disconnected = 1;
+			break;
+		}
+
+
+		/* Break if The Run Loop returns Finished or Stopped. */
+		if (code != kCFRunLoopRunTimedOut &&
+		    code != kCFRunLoopRunHandledSource) {
+			/* There was some kind of error. Setting
+			   shutdown seems to make sense, but
+			   there may be something else more appropriate */
+			dev->shutdown_thread = 1;
+			break;
+		}
+	}
+
+	/* Now that the read thread is stopping, Wake any threads which are
+	   waiting on data (in hid_read_timeout()). Do this under a mutex to
+	   make sure that a thread which is about to go to sleep waiting on
+	   the condition actually will go to sleep before the condition is
+	   signaled. */
+	pthread_mutex_lock(&dev->mutex);
+	pthread_cond_broadcast(&dev->condition);
+	pthread_mutex_unlock(&dev->mutex);
+
+	/* Wait here until hid_close() is called and makes it past
+	   the call to CFRunLoopWakeUp(). This thread still needs to
+	   be valid when that function is called on the other thread. */
+	pthread_barrier_wait(&dev->shutdown_barrier);
+
+	return NULL;
+}
+
+/* hid_open_path()
+ *
+ * path must be a valid path to an IOHIDDevice in the IOService plane
+ * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver"
+ */
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+	hid_device *dev = NULL;
+	io_registry_entry_t entry = MACH_PORT_NULL;
+
+	dev = new_hid_device();
+
+	/* Set up the HID Manager if it hasn't been done */
+	if (hid_init() < 0)
+		return NULL;
+
+	/* Get the IORegistry entry for the given path */
+	entry = IORegistryEntryFromPath(kIOMasterPortDefault, path);
+	if (entry == MACH_PORT_NULL) {
+		/* Path wasn't valid (maybe device was removed?) */
+		goto return_error;
+	}
+
+	/* Create an IOHIDDevice for the entry */
+	dev->device_handle = IOHIDDeviceCreate(kCFAllocatorDefault, entry);
+	if (dev->device_handle == NULL) {
+		/* Error creating the HID device */
+		goto return_error;
+	}
+
+	/* Open the IOHIDDevice */
+	IOReturn ret = IOHIDDeviceOpen(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
+	if (ret == kIOReturnSuccess) {
+		char str[32];
+
+		/* Create the buffers for receiving data */
+		dev->max_input_report_len = (CFIndex) get_max_report_length(dev->device_handle);
+		dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
+
+		/* Create the Run Loop Mode for this device.
+		   printing the reference seems to work. */
+		sprintf(str, "HIDAPI_%p", dev->device_handle);
+		dev->run_loop_mode =
+			CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
+
+		/* Attach the device to a Run Loop */
+		IOHIDDeviceRegisterInputReportCallback(
+			dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+			&hid_report_callback, dev);
+		IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);
+
+		/* Start the read thread */
+		pthread_create(&dev->thread, NULL, read_thread, dev);
+
+		/* Wait here for the read thread to be initialized. */
+		pthread_barrier_wait(&dev->barrier);
+
+		IOObjectRelease(entry);
+		return dev;
+	}
+	else {
+		goto return_error;
+	}
+
+return_error:
+	if (dev->device_handle != NULL)
+		CFRelease(dev->device_handle);
+
+	if (entry != MACH_PORT_NULL)
+		IOObjectRelease(entry);
+
+	free_hid_device(dev);
+	return NULL;
+}
+
+static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
+{
+	const unsigned char *data_to_send;
+	size_t length_to_send;
+	IOReturn res;
+
+	/* Return if the device has been disconnected. */
+	if (dev->disconnected)
+		return -1;
+
+	if (data[0] == 0x0) {
+		/* Not using numbered Reports.
+		   Don't send the report number. */
+		data_to_send = data+1;
+		length_to_send = length-1;
+	}
+	else {
+		/* Using numbered Reports.
+		   Send the Report Number */
+		data_to_send = data;
+		length_to_send = length;
+	}
+
+	if (!dev->disconnected) {
+		res = IOHIDDeviceSetReport(dev->device_handle,
+					   type,
+					   data[0], /* Report ID*/
+					   data_to_send, length_to_send);
+
+		if (res == kIOReturnSuccess) {
+			return length;
+		}
+		else
+			return -1;
+	}
+
+	return -1;
+}
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+	return set_report(dev, kIOHIDReportTypeOutput, data, length);
+}
+
+/* Helper function, so that this isn't duplicated in hid_read(). */
+static int return_data(hid_device *dev, unsigned char *data, size_t length)
+{
+	/* Copy the data out of the linked list item (rpt) into the
+	   return buffer (data), and delete the liked list item. */
+	struct input_report *rpt = dev->input_reports;
+	size_t len = (length < rpt->len)? length: rpt->len;
+	memcpy(data, rpt->data, len);
+	dev->input_reports = rpt->next;
+	free(rpt->data);
+	free(rpt);
+	return len;
+}
+
+static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+	while (!dev->input_reports) {
+		int res = pthread_cond_wait(cond, mutex);
+		if (res != 0)
+			return res;
+
+		/* A res of 0 means we may have been signaled or it may
+		   be a spurious wakeup. Check to see that there's acutally
+		   data in the queue before returning, and if not, go back
+		   to sleep. See the pthread_cond_timedwait() man page for
+		   details. */
+
+		if (dev->shutdown_thread || dev->disconnected)
+			return -1;
+	}
+
+	return 0;
+}
+
+static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+	while (!dev->input_reports) {
+		int res = pthread_cond_timedwait(cond, mutex, abstime);
+		if (res != 0)
+			return res;
+
+		/* A res of 0 means we may have been signaled or it may
+		   be a spurious wakeup. Check to see that there's acutally
+		   data in the queue before returning, and if not, go back
+		   to sleep. See the pthread_cond_timedwait() man page for
+		   details. */
+
+		if (dev->shutdown_thread || dev->disconnected)
+			return -1;
+	}
+
+	return 0;
+
+}
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+	int bytes_read = -1;
+
+	/* Lock the access to the report list. */
+	pthread_mutex_lock(&dev->mutex);
+
+	/* There's an input report queued up. Return it. */
+	if (dev->input_reports) {
+		/* Return the first one */
+		bytes_read = return_data(dev, data, length);
+		goto ret;
+	}
+
+	/* Return if the device has been disconnected. */
+	if (dev->disconnected) {
+		bytes_read = -1;
+		goto ret;
+	}
+
+	if (dev->shutdown_thread) {
+		/* This means the device has been closed (or there
+		   has been an error. An error code of -1 should
+		   be returned. */
+		bytes_read = -1;
+		goto ret;
+	}
+
+	/* There is no data. Go to sleep and wait for data. */
+
+	if (milliseconds == -1) {
+		/* Blocking */
+		int res;
+		res = cond_wait(dev, &dev->condition, &dev->mutex);
+		if (res == 0)
+			bytes_read = return_data(dev, data, length);
+		else {
+			/* There was an error, or a device disconnection. */
+			bytes_read = -1;
+		}
+	}
+	else if (milliseconds > 0) {
+		/* Non-blocking, but called with timeout. */
+		int res;
+		struct timespec ts;
+		struct timeval tv;
+		gettimeofday(&tv, NULL);
+		TIMEVAL_TO_TIMESPEC(&tv, &ts);
+		ts.tv_sec += milliseconds / 1000;
+		ts.tv_nsec += (milliseconds % 1000) * 1000000;
+		if (ts.tv_nsec >= 1000000000L) {
+			ts.tv_sec++;
+			ts.tv_nsec -= 1000000000L;
+		}
+
+		res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
+		if (res == 0)
+			bytes_read = return_data(dev, data, length);
+		else if (res == ETIMEDOUT)
+			bytes_read = 0;
+		else
+			bytes_read = -1;
+	}
+	else {
+		/* Purely non-blocking */
+		bytes_read = 0;
+	}
+
+ret:
+	/* Unlock */
+	pthread_mutex_unlock(&dev->mutex);
+	return bytes_read;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+	/* All Nonblocking operation is handled by the library. */
+	dev->blocking = !nonblock;
+
+	return 0;
+}
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+	return set_report(dev, kIOHIDReportTypeFeature, data, length);
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	CFIndex len = length;
+	IOReturn res;
+
+	/* Return if the device has been unplugged. */
+	if (dev->disconnected)
+		return -1;
+
+	res = IOHIDDeviceGetReport(dev->device_handle,
+	                           kIOHIDReportTypeFeature,
+	                           data[0], /* Report ID */
+	                           data, &len);
+	if (res == kIOReturnSuccess)
+		return len;
+	else
+		return -1;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+	if (!dev)
+		return;
+
+	/* Disconnect the report callback before close. */
+	if (!dev->disconnected) {
+		IOHIDDeviceRegisterInputReportCallback(
+			dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+			NULL, dev);
+		IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);
+		IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
+		IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+	}
+
+	/* Cause read_thread() to stop. */
+	dev->shutdown_thread = 1;
+
+	/* Wake up the run thread's event loop so that the thread can exit. */
+	CFRunLoopSourceSignal(dev->source);
+	CFRunLoopWakeUp(dev->run_loop);
+
+	/* Notify the read thread that it can shut down now. */
+	pthread_barrier_wait(&dev->shutdown_barrier);
+
+	/* Wait for read_thread() to end. */
+	pthread_join(dev->thread, NULL);
+
+	/* Close the OS handle to the device, but only if it's not
+	   been unplugged. If it's been unplugged, then calling
+	   IOHIDDeviceClose() will crash. */
+	if (!dev->disconnected) {
+		IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
+	}
+
+	/* Clear out the queue of received reports. */
+	pthread_mutex_lock(&dev->mutex);
+	while (dev->input_reports) {
+		return_data(dev, NULL, 0);
+	}
+	pthread_mutex_unlock(&dev->mutex);
+	CFRelease(dev->device_handle);
+
+	free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_manufacturer_string(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_product_string(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_serial_number(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+	/* TODO: */
+
+	return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+	/* TODO: */
+
+	return NULL;
+}
+
+
+
+
+
+
+
+#if 0
+static int32_t get_location_id(IOHIDDeviceRef device)
+{
+	return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
+}
+
+static int32_t get_usage(IOHIDDeviceRef device)
+{
+	int32_t res;
+	res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
+	if (!res)
+		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
+	return res;
+}
+
+static int32_t get_usage_page(IOHIDDeviceRef device)
+{
+	int32_t res;
+	res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
+	if (!res)
+		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
+	return res;
+}
+
+static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+	return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
+}
+
+
+int main(void)
+{
+	IOHIDManagerRef mgr;
+	int i;
+
+	mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+	IOHIDManagerSetDeviceMatching(mgr, NULL);
+	IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
+
+	CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
+
+	CFIndex num_devices = CFSetGetCount(device_set);
+	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
+	CFSetGetValues(device_set, (const void **) device_array);
+
+	for (i = 0; i < num_devices; i++) {
+		IOHIDDeviceRef dev = device_array[i];
+		printf("Device: %p\n", dev);
+		printf("  %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
+
+		wchar_t serial[256], buf[256];
+		char cbuf[256];
+		get_serial_number(dev, serial, 256);
+
+
+		printf("  Serial: %ls\n", serial);
+		printf("  Loc: %ld\n", get_location_id(dev));
+		get_transport(dev, buf, 256);
+		printf("  Trans: %ls\n", buf);
+		make_path(dev, cbuf, 256);
+		printf("  Path: %s\n", cbuf);
+
+	}
+
+	return 0;
+}
+#endif
+
+
+#elif defined(__linux__)
+
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+ Linux Version - 6/2/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        http://github.com/signal11/hidapi .
+********************************************************/
+
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+/* Unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <poll.h>
+
+/* Linux */
+#include <linux/hidraw.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <libudev.h>
+
+#include "hidapi.h"
+
+/* Definitions from linux/hidraw.h. Since these are new, some distros
+   may not have header files which contain them. */
+#ifndef HIDIOCSFEATURE
+#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
+#endif
+#ifndef HIDIOCGFEATURE
+#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
+#endif
+
+
+/* USB HID device property names */
+const char *device_string_names[] = {
+	"manufacturer",
+	"product",
+	"serial",
+};
+
+/* Symbolic names for the properties above */
+enum device_string_id {
+	DEVICE_STRING_MANUFACTURER,
+	DEVICE_STRING_PRODUCT,
+	DEVICE_STRING_SERIAL,
+
+	DEVICE_STRING_COUNT,
+};
+
+struct hid_device_ {
+	int device_handle;
+	int blocking;
+	int uses_numbered_reports;
+};
+
+
+static __u32 kernel_version = 0;
+
+static __u32 detect_kernel_version(void)
+{
+	struct utsname name;
+	int major, minor, release;
+	int ret;
+
+	uname(&name);
+	ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);
+	if (ret == 3) {
+		return KERNEL_VERSION(major, minor, release);
+	}
+
+	ret = sscanf(name.release, "%d.%d", &major, &minor);
+	if (ret == 2) {
+		return KERNEL_VERSION(major, minor, 0);
+	}
+
+	printf("Couldn't determine kernel version from version string \"%s\"\n", name.release);
+	return 0;
+}
+
+static hid_device *new_hid_device(void)
+{
+	hid_device *dev = calloc(1, sizeof(hid_device));
+	dev->device_handle = -1;
+	dev->blocking = 1;
+	dev->uses_numbered_reports = 0;
+
+	return dev;
+}
+
+
+/* The caller must free the returned string with free(). */
+static wchar_t *utf8_to_wchar_t(const char *utf8)
+{
+	wchar_t *ret = NULL;
+
+	if (utf8) {
+		size_t wlen = mbstowcs(NULL, utf8, 0);
+		if ((size_t) -1 == wlen) {
+			return wcsdup(L"");
+		}
+		ret = calloc(wlen+1, sizeof(wchar_t));
+		mbstowcs(ret, utf8, wlen+1);
+		ret[wlen] = 0x0000;
+	}
+
+	return ret;
+}
+
+/* Get an attribute value from a udev_device and return it as a whar_t
+   string. The returned string must be freed with free() when done.*/
+static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
+{
+	return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));
+}
+
+/* uses_numbered_reports() returns 1 if report_descriptor describes a device
+   which contains numbered reports. */
+static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
+	unsigned int i = 0;
+	int size_code;
+	int data_len, key_size;
+
+	while (i < size) {
+		int key = report_descriptor[i];
+
+		/* Check for the Report ID key */
+		if (key == 0x85/*Report ID*/) {
+			/* This device has a Report ID, which means it uses
+			   numbered reports. */
+			return 1;
+		}
+
+		//printf("key: %02hhx\n", key);
+
+		if ((key & 0xf0) == 0xf0) {
+			/* This is a Long Item. The next byte contains the
+			   length of the data section (value) for this key.
+			   See the HID specification, version 1.11, section
+			   6.2.2.3, titled "Long Items." */
+			if (i+1 < size)
+				data_len = report_descriptor[i+1];
+			else
+				data_len = 0; /* malformed report */
+			key_size = 3;
+		}
+		else {
+			/* This is a Short Item. The bottom two bits of the
+			   key contain the size code for the data section
+			   (value) for this key.  Refer to the HID
+			   specification, version 1.11, section 6.2.2.2,
+			   titled "Short Items." */
+			size_code = key & 0x3;
+			switch (size_code) {
+			case 0:
+			case 1:
+			case 2:
+				data_len = size_code;
+				break;
+			case 3:
+				data_len = 4;
+				break;
+			default:
+				/* Can't ever happen since size_code is & 0x3 */
+				data_len = 0;
+				break;
+			};
+			key_size = 1;
+		}
+
+		/* Skip over this key and it's associated data */
+		i += data_len + key_size;
+	}
+
+	/* Didn't find a Report ID key. Device doesn't use numbered reports. */
+	return 0;
+}
+
+/*
+ * The caller is responsible for free()ing the (newly-allocated) character
+ * strings pointed to by serial_number_utf8 and product_name_utf8 after use.
+ */
+static int
+parse_uevent_info(const char *uevent, int *bus_type,
+	unsigned short *vendor_id, unsigned short *product_id,
+	char **serial_number_utf8, char **product_name_utf8)
+{
+	char *tmp = strdup(uevent);
+	char *saveptr = NULL;
+	char *line;
+	char *key;
+	char *value;
+
+	int found_id = 0;
+	int found_serial = 0;
+	int found_name = 0;
+
+	line = strtok_r(tmp, "\n", &saveptr);
+	while (line != NULL) {
+		/* line: "KEY=value" */
+		key = line;
+		value = strchr(line, '=');
+		if (!value) {
+			goto next_line;
+		}
+		*value = '\0';
+		value++;
+
+		if (strcmp(key, "HID_ID") == 0) {
+			/**
+			 *        type vendor   product
+			 * HID_ID=0003:000005AC:00008242
+			 **/
+			int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);
+			if (ret == 3) {
+				found_id = 1;
+			}
+		} else if (strcmp(key, "HID_NAME") == 0) {
+			/* The caller has to free the product name */
+			*product_name_utf8 = strdup(value);
+			found_name = 1;
+		} else if (strcmp(key, "HID_UNIQ") == 0) {
+			/* The caller has to free the serial number */
+			*serial_number_utf8 = strdup(value);
+			found_serial = 1;
+		}
+
+next_line:
+		line = strtok_r(NULL, "\n", &saveptr);
+	}
+
+	free(tmp);
+	return (found_id && found_name && found_serial);
+}
+
+
+static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)
+{
+	struct udev *udev;
+	struct udev_device *udev_dev, *parent, *hid_dev;
+	struct stat s;
+	int ret = -1;
+        char *serial_number_utf8 = NULL;
+        char *product_name_utf8 = NULL;
+
+	/* Create the udev object */
+	udev = udev_new();
+	if (!udev) {
+		printf("Can't create udev\n");
+		return -1;
+	}
+
+	/* Get the dev_t (major/minor numbers) from the file handle. */
+	ret = fstat(dev->device_handle, &s);
+	if (-1 == ret)
+		return ret;
+	/* Open a udev device from the dev_t. 'c' means character device. */
+	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
+	if (udev_dev) {
+		hid_dev = udev_device_get_parent_with_subsystem_devtype(
+			udev_dev,
+			"hid",
+			NULL);
+		if (hid_dev) {
+			unsigned short dev_vid;
+			unsigned short dev_pid;
+			int bus_type;
+			size_t retm;
+
+			ret = parse_uevent_info(
+			           udev_device_get_sysattr_value(hid_dev, "uevent"),
+			           &bus_type,
+			           &dev_vid,
+			           &dev_pid,
+			           &serial_number_utf8,
+			           &product_name_utf8);
+
+			if (bus_type == BUS_BLUETOOTH) {
+				switch (key) {
+					case DEVICE_STRING_MANUFACTURER:
+						wcsncpy(string, L"", maxlen);
+						ret = 0;
+						break;
+					case DEVICE_STRING_PRODUCT:
+						retm = mbstowcs(string, product_name_utf8, maxlen);
+						ret = (retm == (size_t)-1)? -1: 0;
+						break;
+					case DEVICE_STRING_SERIAL:
+						retm = mbstowcs(string, serial_number_utf8, maxlen);
+						ret = (retm == (size_t)-1)? -1: 0;
+						break;
+					case DEVICE_STRING_COUNT:
+					default:
+						ret = -1;
+						break;
+				}
+			}
+			else {
+				/* This is a USB device. Find its parent USB Device node. */
+				parent = udev_device_get_parent_with_subsystem_devtype(
+					   udev_dev,
+					   "usb",
+					   "usb_device");
+				if (parent) {
+					const char *str;
+					const char *key_str = NULL;
+
+					if (key >= 0 && key < DEVICE_STRING_COUNT) {
+						key_str = device_string_names[key];
+					} else {
+						ret = -1;
+						goto end;
+					}
+
+					str = udev_device_get_sysattr_value(parent, key_str);
+					if (str) {
+						/* Convert the string from UTF-8 to wchar_t */
+						retm = mbstowcs(string, str, maxlen);
+						ret = (retm == (size_t)-1)? -1: 0;
+						goto end;
+					}
+				}
+			}
+		}
+	}
+
+end:
+        free(serial_number_utf8);
+        free(product_name_utf8);
+
+	udev_device_unref(udev_dev);
+	/* parent and hid_dev don't need to be (and can't be) unref'd.
+	   I'm not sure why, but they'll throw double-free() errors. */
+	udev_unref(udev);
+
+	return ret;
+}
+
+int HID_API_EXPORT hid_init(void)
+{
+	const char *locale;
+
+	/* Set the locale if it's not set. */
+	locale = setlocale(LC_CTYPE, NULL);
+	if (!locale)
+		setlocale(LC_CTYPE, "");
+
+	kernel_version = detect_kernel_version();
+
+	return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+	/* Nothing to do for this in the Linux/hidraw implementation. */
+	return 0;
+}
+
+
+struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+	struct udev *udev;
+	struct udev_enumerate *enumerate;
+	struct udev_list_entry *devices, *dev_list_entry;
+
+	struct hid_device_info *root = NULL; /* return object */
+	struct hid_device_info *cur_dev = NULL;
+	struct hid_device_info *prev_dev = NULL; /* previous device */
+
+	hid_init();
+
+	/* Create the udev object */
+	udev = udev_new();
+	if (!udev) {
+		printf("Can't create udev\n");
+		return NULL;
+	}
+
+	/* Create a list of the devices in the 'hidraw' subsystem. */
+	enumerate = udev_enumerate_new(udev);
+	udev_enumerate_add_match_subsystem(enumerate, "hidraw");
+	udev_enumerate_scan_devices(enumerate);
+	devices = udev_enumerate_get_list_entry(enumerate);
+	/* For each item, see if it matches the vid/pid, and if so
+	   create a udev_device record for it */
+	udev_list_entry_foreach(dev_list_entry, devices) {
+		const char *sysfs_path;
+		const char *dev_path;
+		const char *str;
+		struct udev_device *raw_dev; /* The device's hidraw udev node. */
+		struct udev_device *hid_dev; /* The device's HID udev node. */
+		struct udev_device *usb_dev; /* The device's USB udev node. */
+		struct udev_device *intf_dev; /* The device's interface (in the USB sense). */
+		unsigned short dev_vid;
+		unsigned short dev_pid;
+		char *serial_number_utf8 = NULL;
+		char *product_name_utf8 = NULL;
+		int bus_type;
+		int result;
+
+		/* Get the filename of the /sys entry for the device
+		   and create a udev_device object (dev) representing it */
+		sysfs_path = udev_list_entry_get_name(dev_list_entry);
+		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
+		dev_path = udev_device_get_devnode(raw_dev);
+
+		hid_dev = udev_device_get_parent_with_subsystem_devtype(
+			raw_dev,
+			"hid",
+			NULL);
+
+		if (!hid_dev) {
+			/* Unable to find parent hid device. */
+			goto next;
+		}
+
+		result = parse_uevent_info(
+			udev_device_get_sysattr_value(hid_dev, "uevent"),
+			&bus_type,
+			&dev_vid,
+			&dev_pid,
+			&serial_number_utf8,
+			&product_name_utf8);
+
+		if (!result) {
+			/* parse_uevent_info() failed for at least one field. */
+			goto next;
+		}
+
+		if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
+			/* We only know how to handle USB and BT devices. */
+			goto next;
+		}
+
+		/* Check the VID/PID against the arguments */
+		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+		    (product_id == 0x0 || product_id == dev_pid)) {
+			struct hid_device_info *tmp;
+
+			/* VID/PID match. Create the record. */
+			tmp = malloc(sizeof(struct hid_device_info));
+			if (cur_dev) {
+				cur_dev->next = tmp;
+			}
+			else {
+				root = tmp;
+			}
+			prev_dev = cur_dev;
+			cur_dev = tmp;
+
+			/* Fill out the record */
+			cur_dev->next = NULL;
+			cur_dev->path = dev_path? strdup(dev_path): NULL;
+
+			/* VID/PID */
+			cur_dev->vendor_id = dev_vid;
+			cur_dev->product_id = dev_pid;
+
+			/* Serial Number */
+			cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);
+
+			/* Release Number */
+			cur_dev->release_number = 0x0;
+
+			/* Interface Number */
+			cur_dev->interface_number = -1;
+
+			switch (bus_type) {
+				case BUS_USB:
+					/* The device pointed to by raw_dev contains information about
+					   the hidraw device. In order to get information about the
+					   USB device, get the parent device with the
+					   subsystem/devtype pair of "usb"/"usb_device". This will
+					   be several levels up the tree, but the function will find
+					   it. */
+					usb_dev = udev_device_get_parent_with_subsystem_devtype(
+							raw_dev,
+							"usb",
+							"usb_device");
+
+					if (!usb_dev) {
+						/* Free this device */
+						free(cur_dev->serial_number);
+						free(cur_dev->path);
+						free(cur_dev);
+
+						/* Take it off the device list. */
+						if (prev_dev) {
+							prev_dev->next = NULL;
+							cur_dev = prev_dev;
+						}
+						else {
+							cur_dev = root = NULL;
+						}
+
+						goto next;
+					}
+
+					/* Manufacturer and Product strings */
+					cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);
+					cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);
+
+					/* Release Number */
+					str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");
+					cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;
+
+					/* Get a handle to the interface's udev node. */
+					intf_dev = udev_device_get_parent_with_subsystem_devtype(
+							raw_dev,
+							"usb",
+							"usb_interface");
+					if (intf_dev) {
+						str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
+						cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;
+					}
+
+					break;
+
+				case BUS_BLUETOOTH:
+					/* Manufacturer and Product strings */
+					cur_dev->manufacturer_string = wcsdup(L"");
+					cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
+
+					break;
+
+				default:
+					/* Unknown device type - this should never happen, as we
+					 * check for USB and Bluetooth devices above */
+					break;
+			}
+		}
+
+	next:
+		free(serial_number_utf8);
+		free(product_name_utf8);
+		udev_device_unref(raw_dev);
+		/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)
+		   unref()d.  It will cause a double-free() error.  I'm not
+		   sure why.  */
+	}
+	/* Free the enumerator and udev objects. */
+	udev_enumerate_unref(enumerate);
+	udev_unref(udev);
+
+	return root;
+}
+
+void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+	struct hid_device_info *d = devs;
+	while (d) {
+		struct hid_device_info *next = d->next;
+		free(d->path);
+		free(d->serial_number);
+		free(d->manufacturer_string);
+		free(d->product_string);
+		free(d);
+		d = next;
+	}
+}
+
+hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+	struct hid_device_info *devs, *cur_dev;
+	const char *path_to_open = NULL;
+	hid_device *handle = NULL;
+
+	devs = hid_enumerate(vendor_id, product_id);
+	cur_dev = devs;
+	while (cur_dev) {
+		if (cur_dev->vendor_id == vendor_id &&
+		    cur_dev->product_id == product_id) {
+			if (serial_number) {
+				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+					path_to_open = cur_dev->path;
+					break;
+				}
+			}
+			else {
+				path_to_open = cur_dev->path;
+				break;
+			}
+		}
+		cur_dev = cur_dev->next;
+	}
+
+	if (path_to_open) {
+		/* Open the device */
+		handle = hid_open_path(path_to_open);
+	}
+
+	hid_free_enumeration(devs);
+
+	return handle;
+}
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+	hid_device *dev = NULL;
+
+	hid_init();
+
+	dev = new_hid_device();
+
+	/* OPEN HERE */
+	dev->device_handle = open(path, O_RDWR);
+
+	/* If we have a good handle, return it. */
+	if (dev->device_handle > 0) {
+
+		/* Get the report descriptor */
+		int res, desc_size = 0;
+		struct hidraw_report_descriptor rpt_desc;
+
+		memset(&rpt_desc, 0x0, sizeof(rpt_desc));
+
+		/* Get Report Descriptor Size */
+		res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
+		if (res < 0)
+			perror("HIDIOCGRDESCSIZE");
+
+
+		/* Get Report Descriptor */
+		rpt_desc.size = desc_size;
+		res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
+		if (res < 0) {
+			perror("HIDIOCGRDESC");
+		} else {
+			/* Determine if this device uses numbered reports. */
+			dev->uses_numbered_reports =
+				uses_numbered_reports(rpt_desc.value,
+				                      rpt_desc.size);
+		}
+
+		return dev;
+	}
+	else {
+		/* Unable to open any devices. */
+		free(dev);
+		return NULL;
+	}
+}
+
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+	int bytes_written;
+
+	bytes_written = write(dev->device_handle, data, length);
+
+	return bytes_written;
+}
+
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+	int bytes_read;
+
+	if (milliseconds >= 0) {
+		/* Milliseconds is either 0 (non-blocking) or > 0 (contains
+		   a valid timeout). In both cases we want to call poll()
+		   and wait for data to arrive.  Don't rely on non-blocking
+		   operation (O_NONBLOCK) since some kernels don't seem to
+		   properly report device disconnection through read() when
+		   in non-blocking mode.  */
+		int ret;
+		struct pollfd fds;
+
+		fds.fd = dev->device_handle;
+		fds.events = POLLIN;
+		fds.revents = 0;
+		ret = poll(&fds, 1, milliseconds);
+		if (ret == -1 || ret == 0) {
+			/* Error or timeout */
+			return ret;
+		}
+		else {
+			/* Check for errors on the file descriptor. This will
+			   indicate a device disconnection. */
+			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
+				return -1;
+		}
+	}
+
+	bytes_read = read(dev->device_handle, data, length);
+	if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))
+		bytes_read = 0;
+
+	if (bytes_read >= 0 &&
+	    kernel_version != 0 &&
+	    kernel_version < KERNEL_VERSION(2,6,34) &&
+	    dev->uses_numbered_reports) {
+		/* Work around a kernel bug. Chop off the first byte. */
+		memmove(data, data+1, bytes_read);
+		bytes_read--;
+	}
+
+	return bytes_read;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+	return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+	/* Do all non-blocking in userspace using poll(), since it looks
+	   like there's a bug in the kernel in some versions where
+	   read() will not return -1 on disconnection of the USB device */
+
+	dev->blocking = !nonblock;
+	return 0; /* Success */
+}
+
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+	int res;
+
+	res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
+	if (res < 0)
+		perror("ioctl (SFEATURE)");
+
+	return res;
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	int res;
+
+	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
+	if (res < 0)
+		perror("ioctl (GFEATURE)");
+
+
+	return res;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+	if (!dev)
+		return;
+	close(dev->device_handle);
+	free(dev);
+}
+
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+	return -1;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+	return NULL;
+}
+
+#else
+
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+ Linux Version - 6/2/2010
+ Libusb Version - 8/13/2010
+ FreeBSD Version - 11/1/2011
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        http://github.com/signal11/hidapi .
+********************************************************/
+
+#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
+
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <locale.h>
+#include <errno.h>
+
+/* Unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <wchar.h>
+
+/* GNU / LibUSB */
+#include <libusb.h>
+#ifndef __ANDROID__
+#include <iconv.h>
+#endif
+
+#include "hidapi.h"
+
+#ifdef __ANDROID__
+
+/* Barrier implementation because Android/Bionic don't have pthread_barrier.
+   This implementation came from Brent Priddy and was posted on
+   StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int count;
+    int trip_count;
+} pthread_barrier_t;
+
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
+{
+	if(count == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+		return -1;
+	}
+	if(pthread_cond_init(&barrier->cond, 0) < 0) {
+		pthread_mutex_destroy(&barrier->mutex);
+		return -1;
+	}
+	barrier->trip_count = count;
+	barrier->count = 0;
+
+	return 0;
+}
+
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+	pthread_cond_destroy(&barrier->cond);
+	pthread_mutex_destroy(&barrier->mutex);
+	return 0;
+}
+
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+	pthread_mutex_lock(&barrier->mutex);
+	++(barrier->count);
+	if(barrier->count >= barrier->trip_count)
+	{
+		barrier->count = 0;
+		pthread_cond_broadcast(&barrier->cond);
+		pthread_mutex_unlock(&barrier->mutex);
+		return 1;
+	}
+	else
+	{
+		pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+		pthread_mutex_unlock(&barrier->mutex);
+		return 0;
+	}
+}
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef DEBUG_PRINTF
+#define LOG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define LOG(...) do {} while (0)
+#endif
+
+#ifndef __FreeBSD__
+#define DETACH_KERNEL_DRIVER
+#endif
+
+/* Uncomment to enable the retrieval of Usage and Usage Page in
+hid_enumerate(). Warning, on platforms different from FreeBSD
+this is very invasive as it requires the detach
+and re-attach of the kernel driver. See comments inside hid_enumerate().
+libusb HIDAPI programs are encouraged to use the interface number
+instead to differentiate between interfaces on a composite HID device. */
+/*#define INVASIVE_GET_USAGE*/
+
+/* Linked List of input reports received from the device. */
+struct input_report {
+	uint8_t *data;
+	size_t len;
+	struct input_report *next;
+};
+
+
+struct hid_device_ {
+	/* Handle to the actual device. */
+	libusb_device_handle *device_handle;
+
+	/* Endpoint information */
+	int input_endpoint;
+	int output_endpoint;
+	int input_ep_max_packet_size;
+
+	/* The interface number of the HID */
+	int interface;
+
+	/* Indexes of Strings */
+	int manufacturer_index;
+	int product_index;
+	int serial_index;
+
+	/* Whether blocking reads are used */
+	int blocking; /* boolean */
+
+	/* Read thread objects */
+	pthread_t thread;
+	pthread_mutex_t mutex; /* Protects input_reports */
+	pthread_cond_t condition;
+	pthread_barrier_t barrier; /* Ensures correct startup sequence */
+	int shutdown_thread;
+	int cancelled;
+	struct libusb_transfer *transfer;
+
+	/* List of received input reports. */
+	struct input_report *input_reports;
+};
+
+static libusb_context *usb_context = NULL;
+
+uint16_t get_usb_code_for_current_locale(void);
+static int return_data(hid_device *dev, unsigned char *data, size_t length);
+
+static hid_device *new_hid_device(void)
+{
+	hid_device *dev = calloc(1, sizeof(hid_device));
+	dev->blocking = 1;
+
+	pthread_mutex_init(&dev->mutex, NULL);
+	pthread_cond_init(&dev->condition, NULL);
+	pthread_barrier_init(&dev->barrier, NULL, 2);
+
+	return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+	/* Clean up the thread objects */
+	pthread_barrier_destroy(&dev->barrier);
+	pthread_cond_destroy(&dev->condition);
+	pthread_mutex_destroy(&dev->mutex);
+
+	/* Free the device itself */
+	free(dev);
+}
+
+#if 0
+/*TODO: Implement this funciton on hidapi/libusb.. */
+static void register_error(hid_device *device, const char *op)
+{
+
+}
+#endif
+
+#ifdef INVASIVE_GET_USAGE
+/* Get bytes from a HID Report Descriptor.
+   Only call with a num_bytes of 0, 1, 2, or 4. */
+static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur)
+{
+	/* Return if there aren't enough bytes. */
+	if (cur + num_bytes >= len)
+		return 0;
+
+	if (num_bytes == 0)
+		return 0;
+	else if (num_bytes == 1) {
+		return rpt[cur+1];
+	}
+	else if (num_bytes == 2) {
+		return (rpt[cur+2] * 256 + rpt[cur+1]);
+	}
+	else if (num_bytes == 4) {
+		return (rpt[cur+4] * 0x01000000 +
+		        rpt[cur+3] * 0x00010000 +
+		        rpt[cur+2] * 0x00000100 +
+		        rpt[cur+1] * 0x00000001);
+	}
+	else
+		return 0;
+}
+
+/* Retrieves the device's Usage Page and Usage from the report
+   descriptor. The algorithm is simple, as it just returns the first
+   Usage and Usage Page that it finds in the descriptor.
+   The return value is 0 on success and -1 on failure. */
+static int get_usage(uint8_t *report_descriptor, size_t size,
+                     unsigned short *usage_page, unsigned short *usage)
+{
+	unsigned int i = 0;
+	int size_code;
+	int data_len, key_size;
+	int usage_found = 0, usage_page_found = 0;
+
+	while (i < size) {
+		int key = report_descriptor[i];
+		int key_cmd = key & 0xfc;
+
+		//printf("key: %02hhx\n", key);
+
+		if ((key & 0xf0) == 0xf0) {
+			/* This is a Long Item. The next byte contains the
+			   length of the data section (value) for this key.
+			   See the HID specification, version 1.11, section
+			   6.2.2.3, titled "Long Items." */
+			if (i+1 < size)
+				data_len = report_descriptor[i+1];
+			else
+				data_len = 0; /* malformed report */
+			key_size = 3;
+		}
+		else {
+			/* This is a Short Item. The bottom two bits of the
+			   key contain the size code for the data section
+			   (value) for this key.  Refer to the HID
+			   specification, version 1.11, section 6.2.2.2,
+			   titled "Short Items." */
+			size_code = key & 0x3;
+			switch (size_code) {
+			case 0:
+			case 1:
+			case 2:
+				data_len = size_code;
+				break;
+			case 3:
+				data_len = 4;
+				break;
+			default:
+				/* Can't ever happen since size_code is & 0x3 */
+				data_len = 0;
+				break;
+			};
+			key_size = 1;
+		}
+
+		if (key_cmd == 0x4) {
+			*usage_page  = get_bytes(report_descriptor, size, data_len, i);
+			usage_page_found = 1;
+			//printf("Usage Page: %x\n", (uint32_t)*usage_page);
+		}
+		if (key_cmd == 0x8) {
+			*usage = get_bytes(report_descriptor, size, data_len, i);
+			usage_found = 1;
+			//printf("Usage: %x\n", (uint32_t)*usage);
+		}
+
+		if (usage_page_found && usage_found)
+			return 0; /* success */
+
+		/* Skip over this key and it's associated data */
+		i += data_len + key_size;
+	}
+
+	return -1; /* failure */
+}
+#endif /* INVASIVE_GET_USAGE */
+
+#if defined(__FreeBSD__) && __FreeBSD__ < 10
+/* The libusb version included in FreeBSD < 10 doesn't have this function. In
+   mainline libusb, it's inlined in libusb.h. This function will bear a striking
+   resemblance to that one, because there's about one way to code it.
+
+   Note that the data parameter is Unicode in UTF-16LE encoding.
+   Return value is the number of bytes in data, or LIBUSB_ERROR_*.
+ */
+static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
+	uint8_t descriptor_index, uint16_t lang_id,
+	unsigned char *data, int length)
+{
+	return libusb_control_transfer(dev,
+		LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */
+		LIBUSB_REQUEST_GET_DESCRIPTOR,
+		(LIBUSB_DT_STRING << 8) | descriptor_index,
+		lang_id, data, (uint16_t) length, 1000);
+}
+
+#endif
+
+
+/* Get the first language the device says it reports. This comes from
+   USB string #0. */
+static uint16_t get_first_language(libusb_device_handle *dev)
+{
+	uint16_t buf[32];
+	int len;
+
+	/* Get the string from libusb. */
+	len = libusb_get_string_descriptor(dev,
+			0x0, /* String ID */
+			0x0, /* Language */
+			(unsigned char*)buf,
+			sizeof(buf));
+	if (len < 4)
+		return 0x0;
+
+	return buf[1]; /* First two bytes are len and descriptor type. */
+}
+
+static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
+{
+	uint16_t buf[32];
+	int len;
+	int i;
+
+	/* Get the string from libusb. */
+	len = libusb_get_string_descriptor(dev,
+			0x0, /* String ID */
+			0x0, /* Language */
+			(unsigned char*)buf,
+			sizeof(buf));
+	if (len < 4)
+		return 0x0;
+
+
+	len /= 2; /* language IDs are two-bytes each. */
+	/* Start at index 1 because there are two bytes of protocol data. */
+	for (i = 1; i < len; i++) {
+		if (buf[i] == lang)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/* This function returns a newly allocated wide string containing the USB
+   device string numbered by the index. The returned string must be freed
+   by using free(). */
+static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)
+{
+	char buf[512];
+	int len;
+	wchar_t *str = NULL;
+
+#ifndef __ANDROID__ /* we don't use iconv on Android */
+	wchar_t wbuf[256];
+	/* iconv variables */
+	iconv_t ic;
+	size_t inbytes;
+	size_t outbytes;
+	size_t res;
+#ifdef __FreeBSD__
+	const char *inptr;
+#else
+	char *inptr;
+#endif
+	char *outptr;
+#endif
+
+	/* Determine which language to use. */
+	uint16_t lang;
+	lang = get_usb_code_for_current_locale();
+	if (!is_language_supported(dev, lang))
+		lang = get_first_language(dev);
+
+	/* Get the string from libusb. */
+	len = libusb_get_string_descriptor(dev,
+			idx,
+			lang,
+			(unsigned char*)buf,
+			sizeof(buf));
+	if (len < 0)
+		return NULL;
+
+#ifdef __ANDROID__
+
+	/* Bionic does not have iconv support nor wcsdup() function, so it
+	   has to be done manually.  The following code will only work for
+	   code points that can be represented as a single UTF-16 character,
+	   and will incorrectly convert any code points which require more
+	   than one UTF-16 character.
+
+	   Skip over the first character (2-bytes).  */
+	len -= 2;
+	str = malloc((len / 2 + 1) * sizeof(wchar_t));
+	int i;
+	for (i = 0; i < len / 2; i++) {
+		str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
+	}
+	str[len / 2] = 0x00000000;
+
+#else
+
+	/* buf does not need to be explicitly NULL-terminated because
+	   it is only passed into iconv() which does not need it. */
+
+	/* Initialize iconv. */
+	ic = iconv_open("WCHAR_T", "UTF-16LE");
+	if (ic == (iconv_t)-1) {
+		LOG("iconv_open() failed\n");
+		return NULL;
+	}
+
+	/* Convert to native wchar_t (UTF-32 on glibc/BSD systems).
+	   Skip the first character (2-bytes). */
+	inptr = buf+2;
+	inbytes = len-2;
+	outptr = (char*) wbuf;
+	outbytes = sizeof(wbuf);
+	res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
+	if (res == (size_t)-1) {
+		LOG("iconv() failed\n");
+		goto err;
+	}
+
+	/* Write the terminating NULL. */
+	wbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000;
+	if (outbytes >= sizeof(wbuf[0]))
+		*((wchar_t*)outptr) = 0x00000000;
+
+	/* Allocate and copy the string. */
+	str = wcsdup(wbuf);
+
+err:
+	iconv_close(ic);
+
+#endif
+
+	return str;
+}
+
+static char *make_path(libusb_device *dev, int interface_number)
+{
+	char str[64];
+	snprintf(str, sizeof(str), "%04x:%04x:%02x",
+		libusb_get_bus_number(dev),
+		libusb_get_device_address(dev),
+		interface_number);
+	str[sizeof(str)-1] = '\0';
+
+	return strdup(str);
+}
+
+
+int HID_API_EXPORT hid_init(void)
+{
+	if (!usb_context) {
+		const char *locale;
+
+		/* Init Libusb */
+		if (libusb_init(&usb_context))
+			return -1;
+
+		/* Set the locale if it's not set. */
+		locale = setlocale(LC_CTYPE, NULL);
+		if (!locale)
+			setlocale(LC_CTYPE, "");
+	}
+
+	return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+	if (usb_context) {
+		libusb_exit(usb_context);
+		usb_context = NULL;
+	}
+
+	return 0;
+}
+
+struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+	libusb_device **devs;
+	libusb_device *dev;
+	libusb_device_handle *handle;
+	ssize_t num_devs;
+	int i = 0;
+
+	struct hid_device_info *root = NULL; /* return object */
+	struct hid_device_info *cur_dev = NULL;
+
+	if(hid_init() < 0)
+		return NULL;
+
+	num_devs = libusb_get_device_list(usb_context, &devs);
+	if (num_devs < 0)
+		return NULL;
+	while ((dev = devs[i++]) != NULL) {
+		struct libusb_device_descriptor desc;
+		struct libusb_config_descriptor *conf_desc = NULL;
+		int j, k;
+		int interface_num = 0;
+
+		int res = libusb_get_device_descriptor(dev, &desc);
+		unsigned short dev_vid = desc.idVendor;
+		unsigned short dev_pid = desc.idProduct;
+
+		res = libusb_get_active_config_descriptor(dev, &conf_desc);
+		if (res < 0)
+			libusb_get_config_descriptor(dev, 0, &conf_desc);
+		if (conf_desc) {
+			for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+				const struct libusb_interface *intf = &conf_desc->interface[j];
+				for (k = 0; k < intf->num_altsetting; k++) {
+					const struct libusb_interface_descriptor *intf_desc;
+					intf_desc = &intf->altsetting[k];
+					if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+						interface_num = intf_desc->bInterfaceNumber;
+
+						/* Check the VID/PID against the arguments */
+						if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+						    (product_id == 0x0 || product_id == dev_pid)) {
+							struct hid_device_info *tmp;
+
+							/* VID/PID match. Create the record. */
+							tmp = calloc(1, sizeof(struct hid_device_info));
+							if (cur_dev) {
+								cur_dev->next = tmp;
+							}
+							else {
+								root = tmp;
+							}
+							cur_dev = tmp;
+
+							/* Fill out the record */
+							cur_dev->next = NULL;
+							cur_dev->path = make_path(dev, interface_num);
+
+							res = libusb_open(dev, &handle);
+
+							if (res >= 0) {
+								/* Serial Number */
+								if (desc.iSerialNumber > 0)
+									cur_dev->serial_number =
+										get_usb_string(handle, desc.iSerialNumber);
+
+								/* Manufacturer and Product strings */
+								if (desc.iManufacturer > 0)
+									cur_dev->manufacturer_string =
+										get_usb_string(handle, desc.iManufacturer);
+								if (desc.iProduct > 0)
+									cur_dev->product_string =
+										get_usb_string(handle, desc.iProduct);
+
+#ifdef INVASIVE_GET_USAGE
+{
+							/*
+							This section is removed because it is too
+							invasive on the system. Getting a Usage Page
+							and Usage requires parsing the HID Report
+							descriptor. Getting a HID Report descriptor
+							involves claiming the interface. Claiming the
+							interface involves detaching the kernel driver.
+							Detaching the kernel driver is hard on the system
+							because it will unclaim interfaces (if another
+							app has them claimed) and the re-attachment of
+							the driver will sometimes change /dev entry names.
+							It is for these reasons that this section is
+							#if 0. For composite devices, use the interface
+							field in the hid_device_info struct to distinguish
+							between interfaces. */
+								unsigned char data[256];
+#ifdef DETACH_KERNEL_DRIVER
+								int detached = 0;
+								/* Usage Page and Usage */
+								res = libusb_kernel_driver_active(handle, interface_num);
+								if (res == 1) {
+									res = libusb_detach_kernel_driver(handle, interface_num);
+									if (res < 0)
+										LOG("Couldn't detach kernel driver, even though a kernel driver was attached.");
+									else
+										detached = 1;
+								}
+#endif
+								res = libusb_claim_interface(handle, interface_num);
+								if (res >= 0) {
+									/* Get the HID Report Descriptor. */
+									res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
+									if (res >= 0) {
+										unsigned short page=0, usage=0;
+										/* Parse the usage and usage page
+										   out of the report descriptor. */
+										get_usage(data, res,  &page, &usage);
+										cur_dev->usage_page = page;
+										cur_dev->usage = usage;
+									}
+									else
+										LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res);
+
+									/* Release the interface */
+									res = libusb_release_interface(handle, interface_num);
+									if (res < 0)
+										LOG("Can't release the interface.\n");
+								}
+								else
+									LOG("Can't claim interface %d\n", res);
+#ifdef DETACH_KERNEL_DRIVER
+								/* Re-attach kernel driver if necessary. */
+								if (detached) {
+									res = libusb_attach_kernel_driver(handle, interface_num);
+									if (res < 0)
+										LOG("Couldn't re-attach kernel driver.\n");
+								}
+#endif
+}
+#endif /* INVASIVE_GET_USAGE */
+
+								libusb_close(handle);
+							}
+							/* VID/PID */
+							cur_dev->vendor_id = dev_vid;
+							cur_dev->product_id = dev_pid;
+
+							/* Release Number */
+							cur_dev->release_number = desc.bcdDevice;
+
+							/* Interface Number */
+							cur_dev->interface_number = interface_num;
+						}
+					}
+				} /* altsettings */
+			} /* interfaces */
+			libusb_free_config_descriptor(conf_desc);
+		}
+	}
+
+	libusb_free_device_list(devs, 1);
+
+	return root;
+}
+
+void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+	struct hid_device_info *d = devs;
+	while (d) {
+		struct hid_device_info *next = d->next;
+		free(d->path);
+		free(d->serial_number);
+		free(d->manufacturer_string);
+		free(d->product_string);
+		free(d);
+		d = next;
+	}
+}
+
+hid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+	struct hid_device_info *devs, *cur_dev;
+	const char *path_to_open = NULL;
+	hid_device *handle = NULL;
+
+	devs = hid_enumerate(vendor_id, product_id);
+	cur_dev = devs;
+	while (cur_dev) {
+		if (cur_dev->vendor_id == vendor_id &&
+		    cur_dev->product_id == product_id) {
+			if (serial_number) {
+				if (cur_dev->serial_number &&
+				    wcscmp(serial_number, cur_dev->serial_number) == 0) {
+					path_to_open = cur_dev->path;
+					break;
+				}
+			}
+			else {
+				path_to_open = cur_dev->path;
+				break;
+			}
+		}
+		cur_dev = cur_dev->next;
+	}
+
+	if (path_to_open) {
+		/* Open the device */
+		handle = hid_open_path(path_to_open);
+	}
+
+	hid_free_enumeration(devs);
+
+	return handle;
+}
+
+static void read_callback(struct libusb_transfer *transfer)
+{
+	hid_device *dev = transfer->user_data;
+	int res;
+
+	if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+
+		struct input_report *rpt = malloc(sizeof(*rpt));
+		rpt->data = malloc(transfer->actual_length);
+		memcpy(rpt->data, transfer->buffer, transfer->actual_length);
+		rpt->len = transfer->actual_length;
+		rpt->next = NULL;
+
+		pthread_mutex_lock(&dev->mutex);
+
+		/* Attach the new report object to the end of the list. */
+		if (dev->input_reports == NULL) {
+			/* The list is empty. Put it at the root. */
+			dev->input_reports = rpt;
+			pthread_cond_signal(&dev->condition);
+		}
+		else {
+			/* Find the end of the list and attach. */
+			struct input_report *cur = dev->input_reports;
+			int num_queued = 0;
+			while (cur->next != NULL) {
+				cur = cur->next;
+				num_queued++;
+			}
+			cur->next = rpt;
+
+			/* Pop one off if we've reached 30 in the queue. This
+			   way we don't grow forever if the user never reads
+			   anything from the device. */
+			if (num_queued > 30) {
+				return_data(dev, NULL, 0);
+			}
+		}
+		pthread_mutex_unlock(&dev->mutex);
+	}
+	else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
+		dev->shutdown_thread = 1;
+		dev->cancelled = 1;
+		return;
+	}
+	else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
+		dev->shutdown_thread = 1;
+		dev->cancelled = 1;
+		return;
+	}
+	else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
+		//LOG("Timeout (normal)\n");
+	}
+	else {
+		LOG("Unknown transfer code: %d\n", transfer->status);
+	}
+
+	/* Re-submit the transfer object. */
+	res = libusb_submit_transfer(transfer);
+	if (res != 0) {
+		LOG("Unable to submit URB. libusb error code: %d\n", res);
+		dev->shutdown_thread = 1;
+		dev->cancelled = 1;
+	}
+}
+
+
+static void *read_thread(void *param)
+{
+	hid_device *dev = param;
+	unsigned char *buf;
+	const size_t length = dev->input_ep_max_packet_size;
+
+	/* Set up the transfer object. */
+	buf = malloc(length);
+	dev->transfer = libusb_alloc_transfer(0);
+	libusb_fill_interrupt_transfer(dev->transfer,
+		dev->device_handle,
+		dev->input_endpoint,
+		buf,
+		length,
+		read_callback,
+		dev,
+		5000/*timeout*/);
+
+	/* Make the first submission. Further submissions are made
+	   from inside read_callback() */
+	libusb_submit_transfer(dev->transfer);
+
+	/* Notify the main thread that the read thread is up and running. */
+	pthread_barrier_wait(&dev->barrier);
+
+	/* Handle all the events. */
+	while (!dev->shutdown_thread) {
+		int res;
+		res = libusb_handle_events(usb_context);
+		if (res < 0) {
+			/* There was an error. */
+			LOG("read_thread(): libusb reports error # %d\n", res);
+
+			/* Break out of this loop only on fatal error.*/
+			if (res != LIBUSB_ERROR_BUSY &&
+			    res != LIBUSB_ERROR_TIMEOUT &&
+			    res != LIBUSB_ERROR_OVERFLOW &&
+			    res != LIBUSB_ERROR_INTERRUPTED) {
+				break;
+			}
+		}
+	}
+
+	/* Cancel any transfer that may be pending. This call will fail
+	   if no transfers are pending, but that's OK. */
+	libusb_cancel_transfer(dev->transfer);
+
+	while (!dev->cancelled)
+		libusb_handle_events_completed(usb_context, &dev->cancelled);
+
+	/* Now that the read thread is stopping, Wake any threads which are
+	   waiting on data (in hid_read_timeout()). Do this under a mutex to
+	   make sure that a thread which is about to go to sleep waiting on
+	   the condition actually will go to sleep before the condition is
+	   signaled. */
+	pthread_mutex_lock(&dev->mutex);
+	pthread_cond_broadcast(&dev->condition);
+	pthread_mutex_unlock(&dev->mutex);
+
+	/* The dev->transfer->buffer and dev->transfer objects are cleaned up
+	   in hid_close(). They are not cleaned up here because this thread
+	   could end either due to a disconnect or due to a user
+	   call to hid_close(). In both cases the objects can be safely
+	   cleaned up after the call to pthread_join() (in hid_close()), but
+	   since hid_close() calls libusb_cancel_transfer(), on these objects,
+	   they can not be cleaned up here. */
+
+	return NULL;
+}
+
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+	hid_device *dev = NULL;
+
+	libusb_device **devs;
+	libusb_device *usb_dev;
+	int res;
+	int d = 0;
+	int good_open = 0;
+
+	if(hid_init() < 0)
+		return NULL;
+
+	dev = new_hid_device();
+
+	libusb_get_device_list(usb_context, &devs);
+	while ((usb_dev = devs[d++]) != NULL) {
+		struct libusb_device_descriptor desc;
+		struct libusb_config_descriptor *conf_desc = NULL;
+		int i,j,k;
+		libusb_get_device_descriptor(usb_dev, &desc);
+
+		if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)
+			continue;
+		for (j = 0; j < conf_desc->bNumInterfaces; j++) {
+			const struct libusb_interface *intf = &conf_desc->interface[j];
+			for (k = 0; k < intf->num_altsetting; k++) {
+				const struct libusb_interface_descriptor *intf_desc;
+				intf_desc = &intf->altsetting[k];
+				if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+					char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
+					if (!strcmp(dev_path, path)) {
+						/* Matched Paths. Open this device */
+
+						/* OPEN HERE */
+						res = libusb_open(usb_dev, &dev->device_handle);
+						if (res < 0) {
+							LOG("can't open device\n");
+							free(dev_path);
+							break;
+						}
+						good_open = 1;
+#ifdef DETACH_KERNEL_DRIVER
+						/* Detach the kernel driver, but only if the
+						   device is managed by the kernel */
+						if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
+							res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
+							if (res < 0) {
+								libusb_close(dev->device_handle);
+								LOG("Unable to detach Kernel Driver\n");
+								free(dev_path);
+								good_open = 0;
+								break;
+							}
+						}
+#endif
+						res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
+						if (res < 0) {
+							LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
+							free(dev_path);
+							libusb_close(dev->device_handle);
+							good_open = 0;
+							break;
+						}
+
+						/* Store off the string descriptor indexes */
+						dev->manufacturer_index = desc.iManufacturer;
+						dev->product_index      = desc.iProduct;
+						dev->serial_index       = desc.iSerialNumber;
+
+						/* Store off the interface number */
+						dev->interface = intf_desc->bInterfaceNumber;
+
+						/* Find the INPUT and OUTPUT endpoints. An
+						   OUTPUT endpoint is not required. */
+						for (i = 0; i < intf_desc->bNumEndpoints; i++) {
+							const struct libusb_endpoint_descriptor *ep
+								= &intf_desc->endpoint[i];
+
+							/* Determine the type and direction of this
+							   endpoint. */
+							int is_interrupt =
+								(ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+							      == LIBUSB_TRANSFER_TYPE_INTERRUPT;
+							int is_output =
+								(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+							      == LIBUSB_ENDPOINT_OUT;
+							int is_input =
+								(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+							      == LIBUSB_ENDPOINT_IN;
+
+							/* Decide whether to use it for input or output. */
+							if (dev->input_endpoint == 0 &&
+							    is_interrupt && is_input) {
+								/* Use this endpoint for INPUT */
+								dev->input_endpoint = ep->bEndpointAddress;
+								dev->input_ep_max_packet_size = ep->wMaxPacketSize;
+							}
+							if (dev->output_endpoint == 0 &&
+							    is_interrupt && is_output) {
+								/* Use this endpoint for OUTPUT */
+								dev->output_endpoint = ep->bEndpointAddress;
+							}
+						}
+
+						pthread_create(&dev->thread, NULL, read_thread, dev);
+
+						/* Wait here for the read thread to be initialized. */
+						pthread_barrier_wait(&dev->barrier);
+
+					}
+					free(dev_path);
+				}
+			}
+		}
+		libusb_free_config_descriptor(conf_desc);
+
+	}
+
+	libusb_free_device_list(devs, 1);
+
+	/* If we have a good handle, return it. */
+	if (good_open) {
+		return dev;
+	}
+	else {
+		/* Unable to open any devices. */
+		free_hid_device(dev);
+		return NULL;
+	}
+}
+
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+	int res;
+	int report_number = data[0];
+	int skipped_report_id = 0;
+
+	if (report_number == 0x0) {
+		data++;
+		length--;
+		skipped_report_id = 1;
+	}
+
+
+	if (dev->output_endpoint <= 0) {
+		/* No interrupt out endpoint. Use the Control Endpoint */
+		res = libusb_control_transfer(dev->device_handle,
+			LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
+			0x09/*HID Set_Report*/,
+			(2/*HID output*/ << 8) | report_number,
+			dev->interface,
+			(unsigned char *)data, length,
+			1000/*timeout millis*/);
+
+		if (res < 0)
+			return -1;
+
+		if (skipped_report_id)
+			length++;
+
+		return length;
+	}
+	else {
+		/* Use the interrupt out endpoint */
+		int actual_length;
+		res = libusb_interrupt_transfer(dev->device_handle,
+			dev->output_endpoint,
+			(unsigned char*)data,
+			length,
+			&actual_length, 1000);
+
+		if (res < 0)
+			return -1;
+
+		if (skipped_report_id)
+			actual_length++;
+
+		return actual_length;
+	}
+}
+
+/* Helper function, to simplify hid_read().
+   This should be called with dev->mutex locked. */
+static int return_data(hid_device *dev, unsigned char *data, size_t length)
+{
+	/* Copy the data out of the linked list item (rpt) into the
+	   return buffer (data), and delete the liked list item. */
+	struct input_report *rpt = dev->input_reports;
+	size_t len = (length < rpt->len)? length: rpt->len;
+	if (len > 0)
+		memcpy(data, rpt->data, len);
+	dev->input_reports = rpt->next;
+	free(rpt->data);
+	free(rpt);
+	return len;
+}
+
+static void cleanup_mutex(void *param)
+{
+	hid_device *dev = param;
+	pthread_mutex_unlock(&dev->mutex);
+}
+
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+	int bytes_read = -1;
+
+#if 0
+	int transferred;
+	int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000);
+	LOG("transferred: %d\n", transferred);
+	return transferred;
+#endif
+
+	pthread_mutex_lock(&dev->mutex);
+	pthread_cleanup_push(&cleanup_mutex, dev);
+
+	/* There's an input report queued up. Return it. */
+	if (dev->input_reports) {
+		/* Return the first one */
+		bytes_read = return_data(dev, data, length);
+		goto ret;
+	}
+
+	if (dev->shutdown_thread) {
+		/* This means the device has been disconnected.
+		   An error code of -1 should be returned. */
+		bytes_read = -1;
+		goto ret;
+	}
+
+	if (milliseconds == -1) {
+		/* Blocking */
+		while (!dev->input_reports && !dev->shutdown_thread) {
+			pthread_cond_wait(&dev->condition, &dev->mutex);
+		}
+		if (dev->input_reports) {
+			bytes_read = return_data(dev, data, length);
+		}
+	}
+	else if (milliseconds > 0) {
+		/* Non-blocking, but called with timeout. */
+		int res;
+		struct timespec ts;
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += milliseconds / 1000;
+		ts.tv_nsec += (milliseconds % 1000) * 1000000;
+		if (ts.tv_nsec >= 1000000000L) {
+			ts.tv_sec++;
+			ts.tv_nsec -= 1000000000L;
+		}
+
+		while (!dev->input_reports && !dev->shutdown_thread) {
+			res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
+			if (res == 0) {
+				if (dev->input_reports) {
+					bytes_read = return_data(dev, data, length);
+					break;
+				}
+
+				/* If we're here, there was a spurious wake up
+				   or the read thread was shutdown. Run the
+				   loop again (ie: don't break). */
+			}
+			else if (res == ETIMEDOUT) {
+				/* Timed out. */
+				bytes_read = 0;
+				break;
+			}
+			else {
+				/* Error. */
+				bytes_read = -1;
+				break;
+			}
+		}
+	}
+	else {
+		/* Purely non-blocking */
+		bytes_read = 0;
+	}
+
+ret:
+	pthread_mutex_unlock(&dev->mutex);
+	pthread_cleanup_pop(0);
+
+	return bytes_read;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+	return hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+	dev->blocking = !nonblock;
+
+	return 0;
+}
+
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+	int res = -1;
+	int skipped_report_id = 0;
+	int report_number = data[0];
+
+	if (report_number == 0x0) {
+		data++;
+		length--;
+		skipped_report_id = 1;
+	}
+
+	res = libusb_control_transfer(dev->device_handle,
+		LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
+		0x09/*HID set_report*/,
+		(3/*HID feature*/ << 8) | report_number,
+		dev->interface,
+		(unsigned char *)data, length,
+		1000/*timeout millis*/);
+
+	if (res < 0)
+		return -1;
+
+	/* Account for the report ID */
+	if (skipped_report_id)
+		length++;
+
+	return length;
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	int res = -1;
+	int skipped_report_id = 0;
+	int report_number = data[0];
+
+	if (report_number == 0x0) {
+		/* Offset the return buffer by 1, so that the report ID
+		   will remain in byte 0. */
+		data++;
+		length--;
+		skipped_report_id = 1;
+	}
+	res = libusb_control_transfer(dev->device_handle,
+		LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
+		0x01/*HID get_report*/,
+		(3/*HID feature*/ << 8) | report_number,
+		dev->interface,
+		(unsigned char *)data, length,
+		1000/*timeout millis*/);
+
+	if (res < 0)
+		return -1;
+
+	if (skipped_report_id)
+		res++;
+
+	return res;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+	if (!dev)
+		return;
+
+	/* Cause read_thread() to stop. */
+	dev->shutdown_thread = 1;
+	libusb_cancel_transfer(dev->transfer);
+
+	/* Wait for read_thread() to end. */
+	pthread_join(dev->thread, NULL);
+
+	/* Clean up the Transfer objects allocated in read_thread(). */
+	free(dev->transfer->buffer);
+	libusb_free_transfer(dev->transfer);
+
+	/* release the interface */
+	libusb_release_interface(dev->device_handle, dev->interface);
+
+	/* Close the handle */
+	libusb_close(dev->device_handle);
+
+	/* Clear out the queue of received reports. */
+	pthread_mutex_lock(&dev->mutex);
+	while (dev->input_reports) {
+		return_data(dev, NULL, 0);
+	}
+	pthread_mutex_unlock(&dev->mutex);
+
+	free_hid_device(dev);
+}
+
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return hid_get_indexed_string(dev, dev->product_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+	return hid_get_indexed_string(dev, dev->serial_index, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+	wchar_t *str;
+
+	str = get_usb_string(dev->device_handle, string_index);
+	if (str) {
+		wcsncpy(string, str, maxlen);
+		string[maxlen-1] = L'\0';
+		free(str);
+		return 0;
+	}
+	else
+		return -1;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+	return NULL;
+}
+
+
+struct lang_map_entry {
+	const char *name;
+	const char *string_code;
+	uint16_t usb_code;
+};
+
+#define LANG(name,code,usb_code) { name, code, usb_code }
+static struct lang_map_entry lang_map[] = {
+	LANG("Afrikaans", "af", 0x0436),
+	LANG("Albanian", "sq", 0x041C),
+	LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801),
+	LANG("Arabic - Bahrain", "ar_bh", 0x3C01),
+	LANG("Arabic - Algeria", "ar_dz", 0x1401),
+	LANG("Arabic - Egypt", "ar_eg", 0x0C01),
+	LANG("Arabic - Iraq", "ar_iq", 0x0801),
+	LANG("Arabic - Jordan", "ar_jo", 0x2C01),
+	LANG("Arabic - Kuwait", "ar_kw", 0x3401),
+	LANG("Arabic - Lebanon", "ar_lb", 0x3001),
+	LANG("Arabic - Libya", "ar_ly", 0x1001),
+	LANG("Arabic - Morocco", "ar_ma", 0x1801),
+	LANG("Arabic - Oman", "ar_om", 0x2001),
+	LANG("Arabic - Qatar", "ar_qa", 0x4001),
+	LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401),
+	LANG("Arabic - Syria", "ar_sy", 0x2801),
+	LANG("Arabic - Tunisia", "ar_tn", 0x1C01),
+	LANG("Arabic - Yemen", "ar_ye", 0x2401),
+	LANG("Armenian", "hy", 0x042B),
+	LANG("Azeri - Latin", "az_az", 0x042C),
+	LANG("Azeri - Cyrillic", "az_az", 0x082C),
+	LANG("Basque", "eu", 0x042D),
+	LANG("Belarusian", "be", 0x0423),
+	LANG("Bulgarian", "bg", 0x0402),
+	LANG("Catalan", "ca", 0x0403),
+	LANG("Chinese - China", "zh_cn", 0x0804),
+	LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04),
+	LANG("Chinese - Macau SAR", "zh_mo", 0x1404),
+	LANG("Chinese - Singapore", "zh_sg", 0x1004),
+	LANG("Chinese - Taiwan", "zh_tw", 0x0404),
+	LANG("Croatian", "hr", 0x041A),
+	LANG("Czech", "cs", 0x0405),
+	LANG("Danish", "da", 0x0406),
+	LANG("Dutch - Netherlands", "nl_nl", 0x0413),
+	LANG("Dutch - Belgium", "nl_be", 0x0813),
+	LANG("English - Australia", "en_au", 0x0C09),
+	LANG("English - Belize", "en_bz", 0x2809),
+	LANG("English - Canada", "en_ca", 0x1009),
+	LANG("English - Caribbean", "en_cb", 0x2409),
+	LANG("English - Ireland", "en_ie", 0x1809),
+	LANG("English - Jamaica", "en_jm", 0x2009),
+	LANG("English - New Zealand", "en_nz", 0x1409),
+	LANG("English - Phillippines", "en_ph", 0x3409),
+	LANG("English - Southern Africa", "en_za", 0x1C09),
+	LANG("English - Trinidad", "en_tt", 0x2C09),
+	LANG("English - Great Britain", "en_gb", 0x0809),
+	LANG("English - United States", "en_us", 0x0409),
+	LANG("Estonian", "et", 0x0425),
+	LANG("Farsi", "fa", 0x0429),
+	LANG("Finnish", "fi", 0x040B),
+	LANG("Faroese", "fo", 0x0438),
+	LANG("French - France", "fr_fr", 0x040C),
+	LANG("French - Belgium", "fr_be", 0x080C),
+	LANG("French - Canada", "fr_ca", 0x0C0C),
+	LANG("French - Luxembourg", "fr_lu", 0x140C),
+	LANG("French - Switzerland", "fr_ch", 0x100C),
+	LANG("Gaelic - Ireland", "gd_ie", 0x083C),
+	LANG("Gaelic - Scotland", "gd", 0x043C),
+	LANG("German - Germany", "de_de", 0x0407),
+	LANG("German - Austria", "de_at", 0x0C07),
+	LANG("German - Liechtenstein", "de_li", 0x1407),
+	LANG("German - Luxembourg", "de_lu", 0x1007),
+	LANG("German - Switzerland", "de_ch", 0x0807),
+	LANG("Greek", "el", 0x0408),
+	LANG("Hebrew", "he", 0x040D),
+	LANG("Hindi", "hi", 0x0439),
+	LANG("Hungarian", "hu", 0x040E),
+	LANG("Icelandic", "is", 0x040F),
+	LANG("Indonesian", "id", 0x0421),
+	LANG("Italian - Italy", "it_it", 0x0410),
+	LANG("Italian - Switzerland", "it_ch", 0x0810),
+	LANG("Japanese", "ja", 0x0411),
+	LANG("Korean", "ko", 0x0412),
+	LANG("Latvian", "lv", 0x0426),
+	LANG("Lithuanian", "lt", 0x0427),
+	LANG("F.Y.R.O. Macedonia", "mk", 0x042F),
+	LANG("Malay - Malaysia", "ms_my", 0x043E),
+	LANG("Malay – Brunei", "ms_bn", 0x083E),
+	LANG("Maltese", "mt", 0x043A),
+	LANG("Marathi", "mr", 0x044E),
+	LANG("Norwegian - Bokml", "no_no", 0x0414),
+	LANG("Norwegian - Nynorsk", "no_no", 0x0814),
+	LANG("Polish", "pl", 0x0415),
+	LANG("Portuguese - Portugal", "pt_pt", 0x0816),
+	LANG("Portuguese - Brazil", "pt_br", 0x0416),
+	LANG("Raeto-Romance", "rm", 0x0417),
+	LANG("Romanian - Romania", "ro", 0x0418),
+	LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818),
+	LANG("Russian", "ru", 0x0419),
+	LANG("Russian - Republic of Moldova", "ru_mo", 0x0819),
+	LANG("Sanskrit", "sa", 0x044F),
+	LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A),
+	LANG("Serbian - Latin", "sr_sp", 0x081A),
+	LANG("Setsuana", "tn", 0x0432),
+	LANG("Slovenian", "sl", 0x0424),
+	LANG("Slovak", "sk", 0x041B),
+	LANG("Sorbian", "sb", 0x042E),
+	LANG("Spanish - Spain (Traditional)", "es_es", 0x040A),
+	LANG("Spanish - Argentina", "es_ar", 0x2C0A),
+	LANG("Spanish - Bolivia", "es_bo", 0x400A),
+	LANG("Spanish - Chile", "es_cl", 0x340A),
+	LANG("Spanish - Colombia", "es_co", 0x240A),
+	LANG("Spanish - Costa Rica", "es_cr", 0x140A),
+	LANG("Spanish - Dominican Republic", "es_do", 0x1C0A),
+	LANG("Spanish - Ecuador", "es_ec", 0x300A),
+	LANG("Spanish - Guatemala", "es_gt", 0x100A),
+	LANG("Spanish - Honduras", "es_hn", 0x480A),
+	LANG("Spanish - Mexico", "es_mx", 0x080A),
+	LANG("Spanish - Nicaragua", "es_ni", 0x4C0A),
+	LANG("Spanish - Panama", "es_pa", 0x180A),
+	LANG("Spanish - Peru", "es_pe", 0x280A),
+	LANG("Spanish - Puerto Rico", "es_pr", 0x500A),
+	LANG("Spanish - Paraguay", "es_py", 0x3C0A),
+	LANG("Spanish - El Salvador", "es_sv", 0x440A),
+	LANG("Spanish - Uruguay", "es_uy", 0x380A),
+	LANG("Spanish - Venezuela", "es_ve", 0x200A),
+	LANG("Southern Sotho", "st", 0x0430),
+	LANG("Swahili", "sw", 0x0441),
+	LANG("Swedish - Sweden", "sv_se", 0x041D),
+	LANG("Swedish - Finland", "sv_fi", 0x081D),
+	LANG("Tamil", "ta", 0x0449),
+	LANG("Tatar", "tt", 0X0444),
+	LANG("Thai", "th", 0x041E),
+	LANG("Turkish", "tr", 0x041F),
+	LANG("Tsonga", "ts", 0x0431),
+	LANG("Ukrainian", "uk", 0x0422),
+	LANG("Urdu", "ur", 0x0420),
+	LANG("Uzbek - Cyrillic", "uz_uz", 0x0843),
+	LANG("Uzbek – Latin", "uz_uz", 0x0443),
+	LANG("Vietnamese", "vi", 0x042A),
+	LANG("Xhosa", "xh", 0x0434),
+	LANG("Yiddish", "yi", 0x043D),
+	LANG("Zulu", "zu", 0x0435),
+	LANG(NULL, NULL, 0x0),
+};
+
+uint16_t get_usb_code_for_current_locale(void)
+{
+	char *locale;
+	char search_string[64];
+	char *ptr;
+	struct lang_map_entry *lang;
+
+	/* Get the current locale. */
+	locale = setlocale(0, NULL);
+	if (!locale)
+		return 0x0;
+
+	/* Make a copy of the current locale string. */
+	strncpy(search_string, locale, sizeof(search_string));
+	search_string[sizeof(search_string)-1] = '\0';
+
+	/* Chop off the encoding part, and make it lower case. */
+	ptr = search_string;
+	while (*ptr) {
+		*ptr = tolower(*ptr);
+		if (*ptr == '.') {
+			*ptr = '\0';
+			break;
+		}
+		ptr++;
+	}
+
+	/* Find the entry which matches the string code of our locale. */
+	lang = lang_map;
+	while (lang->string_code) {
+		if (!strcmp(lang->string_code, search_string)) {
+			return lang->usb_code;
+		}
+		lang++;
+	}
+
+	/* There was no match. Find with just the language only. */
+	/* Chop off the variant. Chop it off at the '_'. */
+	ptr = search_string;
+	while (*ptr) {
+		*ptr = tolower(*ptr);
+		if (*ptr == '_') {
+			*ptr = '\0';
+			break;
+		}
+		ptr++;
+	}
+
+#if 0 /* TODO: Do we need this? */
+	/* Find the entry which matches the string code of our language. */
+	lang = lang_map;
+	while (lang->string_code) {
+		if (!strcmp(lang->string_code, search_string)) {
+			return lang->usb_code;
+		}
+		lang++;
+	}
+#endif
+
+	/* Found nothing. */
+	return 0x0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/minichlink/hidapi.h b/minichlink/hidapi.h
new file mode 100644
index 0000000000000000000000000000000000000000..59fb4d7d273e5ba0ca9523c8d7f7e31398a21c92
--- /dev/null
+++ b/minichlink/hidapi.h
@@ -0,0 +1,406 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        http://github.com/signal11/hidapi .
+********************************************************/
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+ 
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include <wchar.h>
+
+#ifdef _WIN32
+      #define HID_API_EXPORT __declspec(dllexport)
+      #define HID_API_CALL
+#else
+      #define HID_API_EXPORT /**< API export macro */
+      #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+		struct hid_device_;
+		typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+		/** hidapi info structure */
+		struct hid_device_info {
+			/** Platform-specific device path */
+			char *path;
+			/** Device Vendor ID */
+			unsigned short vendor_id;
+			/** Device Product ID */
+			unsigned short product_id;
+			/** Serial Number */
+			wchar_t *serial_number;
+			/** Device Release Number in binary-coded decimal,
+			    also known as Device Version Number */
+			unsigned short release_number;
+			/** Manufacturer String */
+			wchar_t *manufacturer_string;
+			/** Product string */
+			wchar_t *product_string;
+			/** Usage Page for this Device/Interface
+			    (Windows/Mac only). */
+			unsigned short usage_page;
+			/** Usage for this Device/Interface
+			    (Windows/Mac only).*/
+			unsigned short usage;
+			/** The USB interface which this logical device
+			    represents. Valid on both Linux implementations
+			    in all cases, and valid on the Windows implementation
+			    only if the device contains more than one interface. */
+			int interface_number;
+
+			/** Pointer to the next device */
+			struct hid_device_info *next;
+		};
+
+
+		/** @brief Initialize the HIDAPI library.
+
+			This function initializes the HIDAPI library. Calling it is not
+			strictly necessary, as it will be called automatically by
+			hid_enumerate() and any of the hid_open_*() functions if it is
+			needed.  This function should be called at the beginning of
+			execution however, if there is a chance of HIDAPI handles
+			being opened by different threads simultaneously.
+			
+			@ingroup API
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+		/** @brief Finalize the HIDAPI library.
+
+			This function frees all of the static data associated with
+			HIDAPI. It should be called at the end of execution to avoid
+			memory leaks.
+
+			@ingroup API
+
+		    @returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+		/** @brief Enumerate the HID Devices.
+
+			This function returns a linked list of all the HID devices
+			attached to the system which match vendor_id and product_id.
+			If @p vendor_id is set to 0 then any vendor matches.
+			If @p product_id is set to 0 then any product matches.
+			If @p vendor_id and @p product_id are both set to 0, then
+			all HID devices will be returned.
+
+			@ingroup API
+			@param vendor_id The Vendor ID (VID) of the types of device
+				to open.
+			@param product_id The Product ID (PID) of the types of
+				device to open.
+
+		    @returns
+		    	This function returns a pointer to a linked list of type
+		    	struct #hid_device, containing information about the HID devices
+		    	attached to the system, or NULL in the case of failure. Free
+		    	this linked list by calling hid_free_enumeration().
+		*/
+		struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+		/** @brief Free an enumeration Linked List
+
+		    This function frees a linked list created by hid_enumerate().
+
+			@ingroup API
+		    @param devs Pointer to a list of struct_device returned from
+		    	      hid_enumerate().
+		*/
+		void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+		/** @brief Open a HID device using a Vendor ID (VID), Product ID
+			(PID) and optionally a serial number.
+
+			If @p serial_number is NULL, the first device with the
+			specified VID and PID is opened.
+
+			@ingroup API
+			@param vendor_id The Vendor ID (VID) of the device to open.
+			@param product_id The Product ID (PID) of the device to open.
+			@param serial_number The Serial Number of the device to open
+				               (Optionally NULL).
+
+			@returns
+				This function returns a pointer to a #hid_device object on
+				success or NULL on failure.
+		*/
+		HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+		/** @brief Open a HID device by its path name.
+
+			The path name be determined by calling hid_enumerate(), or a
+			platform-specific path name can be used (eg: /dev/hidraw0 on
+			Linux).
+
+			@ingroup API
+		    @param path The path name of the device to open
+
+			@returns
+				This function returns a pointer to a #hid_device object on
+				success or NULL on failure.
+		*/
+		HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+		/** @brief Write an Output report to a HID device.
+
+			The first byte of @p data[] must contain the Report ID. For
+			devices which only support a single report, this must be set
+			to 0x0. The remaining bytes contain the report data. Since
+			the Report ID is mandatory, calls to hid_write() will always
+			contain one more byte than the report contains. For example,
+			if a hid report is 16 bytes long, 17 bytes must be passed to
+			hid_write(), the Report ID (or 0x0, for devices with a
+			single report), followed by the report data (16 bytes). In
+			this example, the length passed in would be 17.
+
+			hid_write() will send the data on the first OUT endpoint, if
+			one exists. If it does not, it will send the data through
+			the Control Endpoint (Endpoint 0).
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param data The data to send, including the report number as
+				the first byte.
+			@param length The length in bytes of the data to send.
+
+			@returns
+				This function returns the actual number of bytes written and
+				-1 on error.
+		*/
+		int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+		/** @brief Read an Input report from a HID device with timeout.
+
+			Input reports are returned
+			to the host through the INTERRUPT IN endpoint. The first byte will
+			contain the Report number if the device uses numbered reports.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param data A buffer to put the read data into.
+			@param length The number of bytes to read. For devices with
+				multiple reports, make sure to read an extra byte for
+				the report number.
+			@param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+			@returns
+				This function returns the actual number of bytes read and
+				-1 on error. If no packet was available to be read within
+				the timeout period, this function returns 0.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+		/** @brief Read an Input report from a HID device.
+
+			Input reports are returned
+		    to the host through the INTERRUPT IN endpoint. The first byte will
+			contain the Report number if the device uses numbered reports.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param data A buffer to put the read data into.
+			@param length The number of bytes to read. For devices with
+				multiple reports, make sure to read an extra byte for
+				the report number.
+
+			@returns
+				This function returns the actual number of bytes read and
+				-1 on error. If no packet was available to be read and
+				the handle is in non-blocking mode, this function returns 0.
+		*/
+		int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+		/** @brief Set the device handle to be non-blocking.
+
+			In non-blocking mode calls to hid_read() will return
+			immediately with a value of 0 if there is no data to be
+			read. In blocking mode, hid_read() will wait (block) until
+			there is data to read before returning.
+
+			Nonblocking can be turned on and off at any time.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param nonblock enable or not the nonblocking reads
+			 - 1 to enable nonblocking
+			 - 0 to disable nonblocking.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+		/** @brief Send a Feature report to the device.
+
+			Feature reports are sent over the Control endpoint as a
+			Set_Report transfer.  The first byte of @p data[] must
+			contain the Report ID. For devices which only support a
+			single report, this must be set to 0x0. The remaining bytes
+			contain the report data. Since the Report ID is mandatory,
+			calls to hid_send_feature_report() will always contain one
+			more byte than the report contains. For example, if a hid
+			report is 16 bytes long, 17 bytes must be passed to
+			hid_send_feature_report(): the Report ID (or 0x0, for
+			devices which do not use numbered reports), followed by the
+			report data (16 bytes). In this example, the length passed
+			in would be 17.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param data The data to send, including the report number as
+				the first byte.
+			@param length The length in bytes of the data to send, including
+				the report number.
+
+			@returns
+				This function returns the actual number of bytes written and
+				-1 on error.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+		/** @brief Get a feature report from a HID device.
+
+			Set the first byte of @p data[] to the Report ID of the
+			report to be read.  Make sure to allow space for this
+			extra byte in @p data[]. Upon return, the first byte will
+			still contain the Report ID, and the report data will
+			start in data[1].
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param data A buffer to put the read data into, including
+				the Report ID. Set the first byte of @p data[] to the
+				Report ID of the report to be read, or set it to zero
+				if your device does not use numbered reports.
+			@param length The number of bytes to read, including an
+				extra byte for the report ID. The buffer can be longer
+				than the actual report.
+
+			@returns
+				This function returns the number of bytes read plus
+				one for the report ID (which is still in the first
+				byte), or -1 on error.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+		/** @brief Close a HID device.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+		*/
+		void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+		/** @brief Get The Manufacturer String from a HID device.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param string A wide string buffer to put the data into.
+			@param maxlen The length of the buffer in multiples of wchar_t.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+		/** @brief Get The Product String from a HID device.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param string A wide string buffer to put the data into.
+			@param maxlen The length of the buffer in multiples of wchar_t.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+		/** @brief Get The Serial Number String from a HID device.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param string A wide string buffer to put the data into.
+			@param maxlen The length of the buffer in multiples of wchar_t.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+		/** @brief Get a string from a HID device, based on its string index.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+			@param string_index The index of the string to get.
+			@param string A wide string buffer to put the data into.
+			@param maxlen The length of the buffer in multiples of wchar_t.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+		/** @brief Get a string describing the last error which occurred.
+
+			@ingroup API
+			@param device A device handle returned from hid_open().
+
+			@returns
+				This function returns a string containing the last error
+				which occurred or NULL if none has occurred.
+		*/
+		HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c
index 3f1b0c96100d771134b9ae1a016a8aa0123c61f9..f1aee9c8f51f2a84b9cc2ff997dfbb692c07d834 100644
--- a/minichlink/minichlink.c
+++ b/minichlink/minichlink.c
@@ -4,61 +4,60 @@
 // public domain where applicable. 
 
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
-#include "wch_link_base.h"
-
-
-const uint8_t * bootloader = (const uint8_t*)
-"\x21\x11\x22\xca\x26\xc8\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45" \
-"\xb7\x27\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07" \
-"\xb7\x9a\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27" \
-"\x02\x40\x98\x4b\xad\x66\x37\x33\x00\x40\x13\x67\x47\x00\x98\xcb" \
-"\x98\x4b\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b" \
-"\x63\x16\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb" \
-"\x93\x07\xf6\x03\x99\x83\x2e\xc0\x2d\x63\x81\x76\x3e\xc4\xb7\x32" \
-"\x00\x40\xb7\x27\x02\x40\x13\x03\xa3\xaa\xfd\x16\x98\x4b\xb7\x03" \
-"\x02\x00\x33\x67\x77\x00\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67" \
-"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb" \
-"\x02\x47\x13\x07\x07\x04\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x79\xf7" \
-"\x93\x77\x85\x00\xf1\xcf\x93\x07\xf6\x03\x2e\xc0\x99\x83\x37\x27" \
-"\x02\x40\x3e\xc4\x1c\x4b\xc1\x66\x2d\x63\xd5\x8f\x1c\xcb\x37\x07" \
-"\x00\x20\x13\x07\x07\x20\xb7\x27\x02\x40\xb7\x03\x08\x00\xb7\x32" \
-"\x00\x40\x13\x03\xa3\xaa\x94\x4b\xb3\xe6\x76\x00\x94\xcb\xd4\x47" \
-"\x85\x8a\xf5\xfe\x82\x46\xba\x84\x37\x04\x04\x00\x36\xc2\xc1\x46" \
-"\x36\xc6\x92\x46\x84\x40\x11\x07\x84\xc2\x94\x4b\xc1\x8e\x94\xcb" \
-"\xd4\x47\x85\x8a\xb1\xea\x92\x46\xba\x84\x91\x06\x36\xc2\xb2\x46" \
-"\xfd\x16\x36\xc6\xf9\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6\x06\x04" \
-"\x94\xcb\xd4\x47\x85\x8a\x85\xee\xd4\x47\xc1\x8a\x85\xce\xd8\x47" \
-"\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b\x21\x45" \
-"\x75\x8f\x98\xcb\x52\x44\xc2\x44\x61\x01\x02\x90\x23\x20\xd3\x00" \
-"\xf5\xb5\x23\xa0\x62\x00\x3d\xb7\x23\xa0\x62\x00\x55\xb7\x23\xa0" \
-"\x62\x00\xc1\xb7\x82\x46\x93\x86\x06\x04\x36\xc0\xa2\x46\xfd\x16" \
-"\x36\xc4\xb5\xf2\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb" \
-"\x41\x89\x05\xcd\x2e\xc0\x0d\x06\x02\xc4\x09\x82\xb7\x07\x00\x20" \
-"\x32\xc6\x93\x87\x07\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46" \
-"\x8a\x07\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4" \
-"\xa2\x46\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x61\xb7\x41\x45" \
-"\x51\xb7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
-"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
-"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+#include "minichlink.h"
 
 static int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber );
-
-int bootloader_len = 512;
+void TestFunction(void * v );
+struct MiniChlinkFunctions MCF;
 
 int main( int argc, char ** argv )
 {
+	void * dev = 0;
+	if( (dev = TryInit_WCHLinkE()) )
+	{
+		fprintf( stderr, "Found WCH LinkE\n" );
+	}
+	else if( (dev = TryInit_ESP32S2CHFUN()) )
+	{
+		fprintf( stderr, "Found ESP32S2 Programmer\n" );
+	}
+	else
+	{
+		fprintf( stderr, "Error: Could not initialize any supported programmers\n" );
+		return -32;
+	}
+	
+	SetupAutomaticHighLevelFunctions();
+
 	int status;
 	int must_be_end = 0;
 	uint8_t rbuff[1024];
 
-	libusb_device_handle * devh = wch_link_base_setup(0);
+	if( MCF.SetupInterface )
+	{
+		if( MCF.SetupInterface( dev ) < 0 )
+		{
+			fprintf( stderr, "Could not setup interface.\n" );
+			return -33;
+		}
+	}
+
+	//TestFunction( dev );
 
-	int iarg;
-	for( iarg = 1; iarg < argc; iarg++ )
+	int iarg = 1;
+	const char * lastcommand = 0;
+	for( ; iarg < argc; iarg++ )
 	{
 		char * argchar = argv[iarg];
-		if( argchar[0] != '-' ) goto help;
+
+		lastcommand = argchar;
+		if( argchar[0] != '-' )
+		{
+			fprintf( stderr, "Error: Need prefixing - before commands\n" );
+			goto help;
+		}
 		if( must_be_end )
 		{
 			fprintf( stderr, "Error: the command '%c' cannot be followed by other commands.\n", must_be_end );
@@ -68,28 +67,66 @@ int main( int argc, char ** argv )
 keep_going:
 		switch( argchar[1] )
 		{
-			default: goto help;
-			case '3': wch_link_command( devh, "\x81\x0d\x01\x09", 4, 0, 0, 0 ); break;
-			case '5': wch_link_command( devh, "\x81\x0d\x01\x0b", 4, 0, 0, 0 ); break;
-			case 't': wch_link_command( devh, "\x81\x0d\x01\x0a", 4, 0, 0, 0 ); break;
-			case 'f': wch_link_command( devh, "\x81\x0d\x01\x0c", 4, 0, 0, 0 ); break;
+			default:
+				fprintf( stderr, "Error: Unknown command %c\n", argchar[1] );
+				goto help;
+			case '3':
+				if( MCF.Control3v3 )
+					MCF.Control3v3( dev, 1 );
+				else
+					goto unimplemented;
+				break;
+			case '5':
+				if( MCF.Control5v )
+					MCF.Control5v( dev, 1 );
+				else
+					goto unimplemented;
+				break;
+			case 't':
+				if( MCF.Control3v3 )
+					MCF.Control3v3( dev, 0 );
+				else
+					goto unimplemented;
+				break;
+			case 'f':
+				if( MCF.Control5v )
+					MCF.Control5v( dev, 0 );
+				else
+					goto unimplemented;
+				break;
+			case 'u':
+				if( MCF.Unbrick )
+					MCF.Unbrick( dev );
+				else
+					goto unimplemented;
+				break;
 			case 'r': 
-				// This is clearly not the "best" method to exit reset.  I don't know why this combination works.
-				wch_link_multicommands( devh, 3, 4, "\x81\x0b\x01\x01", 4, "\x81\x0d\x01\x02", 4, "\x81\x0d\x01\xff" );
+				if( MCF.HaltMode )
+					MCF.HaltMode( dev, 0 );
+				else
+					goto unimplemented;
 				must_be_end = 'r';
 				break;
 			case 'R':
-				// Part one "immediately" places the part into reset.  Part 2 says when we're done, leave part in reset.
-				wch_link_multicommands( devh, 2, 4, "\x81\x0d\x01\x02", 4, "\x81\x0d\x01\x01" );
+				if( MCF.HaltMode )
+					MCF.HaltMode( dev, 1 );
+				else
+					goto unimplemented;
 				must_be_end = 'R';
 				break;
 
 			// disable NRST pin (turn it into a GPIO)
 			case 'd':  // see "RSTMODE" in datasheet
-				wch_link_multicommands( devh, 2, 11, "\x81\x06\x08\x02\xf7\xff\xff\xff\xff\xff\xff", 4, "\x81\x0b\x01\x01" );
+				if( MCF.ConfigureNRSTAsGPIO )
+					MCF.ConfigureNRSTAsGPIO( dev, 0 );
+				else
+					goto unimplemented;
 				break;
 			case 'D': // see "RSTMODE" in datasheet
-				wch_link_multicommands( devh, 2, 11, "\x81\x06\x08\x02\xff\xff\xff\xff\xff\xff\xff", 4, "\x81\x0b\x01\x01" );
+				if( MCF.ConfigureNRSTAsGPIO )
+					MCF.ConfigureNRSTAsGPIO( dev, 1 );
+				else
+					goto unimplemented;
 				break;
 			// PROTECTION UNTESTED!
 			/*
@@ -119,10 +156,18 @@ keep_going:
 			{
 				int i;
 				int transferred;
-				if( argchar[2] != 0 ) goto help;
+				if( argchar[2] != 0 )
+				{
+					fprintf( stderr, "Error: can't have char after paramter field\n" ); 
+					goto help;
+				}
 				iarg++;
 				argchar = 0; // Stop advancing
-				if( iarg + 2 >= argc ) goto help;
+				if( iarg + 2 >= argc )
+				{
+					fprintf( stderr, "Error: missing file for -o.\n" ); 
+					goto help;
+				}
 				uint64_t offset = SimpleReadNumberInt( argv[iarg++], -1 );
 				uint64_t amount = SimpleReadNumberInt( argv[iarg++], -1 );
 				if( offset > 0xffffffff || amount > 0xffffffff )
@@ -139,52 +184,23 @@ keep_going:
 					fprintf( stderr, "Error: can't open write file \"%s\"\n", argv[iarg] );
 					return -9;
 				}
-				uint32_t * readbuff = malloc( amount );
+				uint8_t * readbuff = malloc( amount );
 				int readbuffplace = 0;
-				wch_link_command( devh, "\x81\x06\x01\x01", 4, 0, 0, 0 );
-
-				// Flush out any pending data.
-				libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, 1 );
-
-				// 3/8 = Read Memory
-				// First 4 bytes are big-endian location.
-				// Next 4 bytes are big-endian amount.
-				uint8_t readop[11] = { 0x81, 0x03, 0x08, };
-				
-				readop[3] = (offset>>24)&0xff;
-				readop[4] = (offset>>16)&0xff;
-				readop[5] = (offset>>8)&0xff;
-				readop[6] = (offset>>0)&0xff;
-
-				readop[7] = (amount>>24)&0xff;
-				readop[8] = (amount>>16)&0xff;
-				readop[9] = (amount>>8)&0xff;
-				readop[10] = (amount>>0)&0xff;
-				
-				wch_link_command( devh, readop, 11, 0, 0, 0 );
-
-				// Perform operation
-				wch_link_command( devh, "\x81\x02\x01\x0c", 4, 0, 0, 0 );
-
-				uint32_t remain = amount;
-				while( remain )
-				{
-					transferred = 0;
-					WCHCHECK( libusb_bulk_transfer( devh, 0x82, rbuff, 1024, &transferred, WCHTIMEOUT ) );
-					memcpy( ((uint8_t*)readbuff) + readbuffplace, rbuff, transferred );
-					readbuffplace += transferred;
-					remain -= transferred;
-				}
 
-				// Flip internal endian.  Must be done separately in case something was unaligned when
-				// reading.
-				for( i = 0; i < readbuffplace/4; i++ )
+				if( MCF.ReadBinaryBlob )
+				{
+					if( MCF.ReadBinaryBlob( dev, offset, amount, readbuff ) < 0 )
+					{
+						fprintf( stderr, "Fault reading device\n" );
+						return -12;
+					}
+				}				
+				else
 				{
-					uint32_t r = readbuff[i];
-					readbuff[i] = (r>>24) | ((r & 0xff0000) >> 8) | ((r & 0xff00)<<8) | (( r & 0xff )<<24); 
+					goto unimplemented;
 				}
-				
-				fwrite( readbuff, readbuffplace, 1, f );
+
+				fwrite( readbuff, amount, 1, f );
 
 				free( readbuff );
 
@@ -197,16 +213,13 @@ keep_going:
 				iarg++;
 				argchar = 0; // Stop advancing
 				if( iarg >= argc ) goto help;
-
 				// Write binary.
 				int i;
 				FILE * f = fopen( argv[iarg], "rb" );
 				fseek( f, 0, SEEK_END );
 				int len = ftell( f );
 				fseek( f, 0, SEEK_SET );
-				int padlen = ((len-1) & (~0x3f)) + 0x40;
-				char * image = malloc( padlen );
-				memset( image, 0xff, padlen );
+				char * image = malloc( len );
 				status = fread( image, len, 1, f );
 				fclose( f );
 	
@@ -221,44 +234,17 @@ keep_going:
 					exit( -9 );
 				}
 
-				int transferred;
-				wch_link_command( devh, "\x81\x06\x01\x01", 4, 0, 0, 0 );
-				wch_link_command( devh, "\x81\x06\x01\x01", 4, 0, 0, 0 ); // Not sure why but it seems to work better when we request twice.
-
-				// This contains the write data quantity, in bytes.  (The last 2 octets)
-				// Then it just rollllls on in.
-				char rksbuff[11] = { 0x81, 0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-				rksbuff[9] = len >> 8;
-				rksbuff[10] = len & 0xff;
-				wch_link_command( devh, rksbuff, 11, 0, 0, 0 );
-				
-				wch_link_command( devh, "\x81\x02\x01\x05", 4, 0, 0, 0 );
-				
-				int pplace = 0;
-				for( pplace = 0; pplace < bootloader_len; pplace += 64 )
-				{
-					WCHCHECK( libusb_bulk_transfer( devh, 0x02, (uint8_t*)(bootloader+pplace), 64, &transferred, WCHTIMEOUT ) );
-				}
-				
-				for( i = 0; i < 10; i++ )
+				if( MCF.WriteBinaryBlob )
 				{
-					wch_link_command( devh, "\x81\x02\x01\x07", 4, &transferred, rbuff, 1024 );
-					if( transferred == 4 && rbuff[0] == 0x82 && rbuff[1] == 0x02 && rbuff[2] == 0x01 && rbuff[3] == 0x07 )
+					if( MCF.WriteBinaryBlob( dev, 0x08000000, len, image ) )
 					{
-						break;
+						fprintf( stderr, "Error: Fault writing image.\n" );
+						return -13;
 					}
-				} 
-				if( i == 10 )
-				{
-					fprintf( stderr, "Error, confusing respones to 02/01/07\n" );
-					exit( -109 );
 				}
-				
-				wch_link_command( devh, "\x81\x02\x01\x02", 4, 0, 0, 0 );
-
-				for( pplace = 0; pplace < padlen; pplace += 64 )
+				else
 				{
-					WCHCHECK( libusb_bulk_transfer( devh, 0x02,image+pplace, 64, &transferred, WCHTIMEOUT ) );
+					goto unimplemented;
 				}
 
 				// Waiting or something on 2.46.2???????  I don't know why the main system does this.
@@ -271,7 +257,8 @@ keep_going:
 		if( argchar && argchar[2] != 0 ) { argchar++; goto keep_going; }
 	}
 
-	wch_link_command( devh, "\x81\x0d\x01\xff", 4, 0, 0, 0);
+	if( MCF.Exit )
+		MCF.Exit( dev );
 
 	return 0;
 
@@ -283,7 +270,8 @@ help:
 	fprintf( stderr, " -5 Enable 5V\n" );
 	fprintf( stderr, " -t Disable 3.3V\n" );
 	fprintf( stderr, " -f Disable 5V\n" );
-	fprintf( stderr, " -r Release from reest\n" );
+	fprintf( stderr, " -u Clear all code flash - by power off (also can unbrick)\n" );
+	fprintf( stderr, " -r Release from Reset\n" );
 	fprintf( stderr, " -R Place into Reset\n" );
 	fprintf( stderr, " -D Configure NRST as GPIO **WARNING** If you do this and you reconfig\n" );
 	fprintf( stderr, "      the SWIO pin (PD1) on boot, your part can never again be programmed!\n" );
@@ -293,6 +281,10 @@ help:
 	fprintf( stderr, " -w [binary image to write]\n" );
 	fprintf( stderr, " -o [memory address, decimal or 0x, try 0x08000000] [size, decimal or 0x, try 16384] [output binary image]\n" );
 	return -1;	
+
+unimplemented:
+	fprintf( stderr, "Error: Command '%s' unimplemented on this programmer.\n", lastcommand );
+	return -1;
 }
 
 
@@ -324,3 +316,146 @@ static int64_t SimpleReadNumberInt( const char * number, int64_t defaultNumber )
 		return ret;
 	}
 }
+
+
+int DefaultSetupInterface( void * dev )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+
+	if( MCF.Control3v3 ) MCF.Control3v3( dev, 1 );
+	if( MCF.DelayUS ) MCF.DelayUS( dev, 16000 );
+	MCF.WriteReg32( dev, SHDWCFGR, 0x5aa50000 | (1<<10) ); // Shadow Config Reg
+	MCF.WriteReg32( dev, CFGR, 0x5aa50000 | (1<<10) ); // CFGR (1<<10 == Allow output from slave)
+	MCF.WriteReg32( dev, CFGR, 0x5aa50000 | (1<<10) ); // Bug in silicon?  If coming out of cold boot, and we don't do our little "song and dance" this has to be called.
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request.
+
+	// Read back chip ID.
+	uint32_t reg;
+	int r = MCF.ReadReg32( dev, DMSTATUS, &reg );
+	if( r >= 0 )
+	{
+		// Valid R.
+		if( reg == 0x00000000 || reg == 0xffffffff )
+		{
+			fprintf( stderr, "Error: Setup chip failed. Got code %08x\n", reg );
+			return -9;
+		}
+		return 0;
+	}
+	else
+	{
+		fprintf( stderr, "Error: Could not read chip code.\n" );
+		return r;
+	}
+}
+
+static int WriteWord( void * dev, uint32_t address_to_write, uint32_t data )
+{
+	int r;
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x0072a023 ); // sw x7,0(x5)
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x00100073 ); // ebreak
+	MCF.WriteReg32( dev, DMDATA0, address_to_write );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00231005 ); // Copy data to x5
+	uint32_t rrv;
+	do
+	{
+		r = MCF.ReadReg32( dev, DMABSTRACTCS, &rrv );
+		if( r ) return r;
+	}
+	while( rrv & (1<<12) );
+	
+	MCF.WriteReg32( dev, DMDATA0, data );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00271007 ); // Copy data to x7, and execute program.
+	do
+	{
+		r = MCF.ReadReg32( dev, DMABSTRACTCS, &rrv );
+		if( r ) return r;
+	}
+	while( rrv & (1<<12) );
+	if( (rrv >> 8 ) & 7 )
+	{
+		fprintf( stderr, "Fault writing memory (DMABSTRACTS = %08x)\n", rrv );
+	}
+	return 0;
+}
+
+int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob_size, uint8_t * blob )
+{
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request.
+	MCF.WriteReg32( dev, DMCONTROL, 0x00000001 ); // Clear Halt Request.
+}
+
+static int ReadWord( void * dev, uint32_t address_to_read, uint32_t * data )
+{
+	int r;
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x0002a303 ); // lw x6,0(x5)
+	MCF.WriteReg32( dev, DMPROGBUF0, 0x00100073 ); // ebreak
+	MCF.WriteReg32( dev, DMDATA0, address_to_read );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00271005 ); // Copy data to x5
+	uint32_t rrv;
+	do
+	{
+		r = MCF.ReadReg32( dev, DMABSTRACTCS, &rrv );
+		if( r ) return r;
+	}
+	while( rrv & (1<<12) );
+	printf( "RRV: %08x\n", rrv );
+	MCF.WriteReg32( dev, DMCOMMAND, 0x00221006 ); // Copy x7 to data0
+	do
+	{
+		r = MCF.ReadReg32( dev, DMABSTRACTCS, &rrv );
+		if( r ) return r;
+	}
+	while( rrv & (1<<12) );
+	printf( "RRV: %08x\n", rrv );
+	if( (rrv >> 8 ) & 7 )
+	{
+		fprintf( stderr, "Fault writing memory (DMABSTRACTS = %08x)\n", rrv );
+	}
+	
+	return MCF.ReadReg32( dev, DMDATA0, data );
+}
+
+int DefaultReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob )
+{
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request.
+	MCF.WriteReg32( dev, DMCONTROL, 0x00000001 ); // Clear Halt Request.
+	
+	
+}
+
+void TestFunction(void * dev )
+{
+	uint32_t rv;
+	int r;
+	
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly.
+	MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request.
+	MCF.WriteReg32( dev, DMCONTROL, 0x00000001 ); // Clear Halt Request.
+
+	r = ReadWord( dev, 0x08000004, &rv );
+	printf( "%d %08x\n", r, rv );
+}
+
+
+
+int SetupAutomaticHighLevelFunctions()
+{
+	// Will populate high-level functions from low-level functions.
+	if( MCF.WriteReg32 == 0 || MCF.ReadReg32 == 0 ) return -5;
+
+	// Else, TODO: Build the high level functions from low level functions.
+	// If a high-level function alrady exists, don't override.
+	
+	if( !MCF.SetupInterface )
+		MCF.SetupInterface = DefaultSetupInterface;
+	if( !MCF.WriteBinaryBlob )
+		MCF.WriteBinaryBlob = DefaultWriteBinaryBlob;
+	if( !MCF.ReadBinaryBlob )
+		MCF.ReadBinaryBlob = DefaultReadBinaryBlob;
+
+}
+
diff --git a/minichlink/minichlink.exe b/minichlink/minichlink.exe
index c0793b3f69d6ebc99cef73b72ba8b3fb6b181085..5c187f5e3995cdace9814183aecea6eedf6fc83d 100644
Binary files a/minichlink/minichlink.exe and b/minichlink/minichlink.exe differ
diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h
new file mode 100644
index 0000000000000000000000000000000000000000..730409c059a232492dcdda79fb34f0834ad87a3d
--- /dev/null
+++ b/minichlink/minichlink.h
@@ -0,0 +1,65 @@
+#ifndef _MINICHLINK_H
+#define _MINICHLINK_H
+
+#include <stdint.h>
+
+struct MiniChlinkFunctions
+{
+	// All functions return 0 if OK, negative number if fault, positive number as status code.
+
+	// Low-level functions, if they exist.
+	int (*WriteReg32)( void * dev, uint8_t reg_7_bit, uint32_t command );
+	int (*ReadReg32)( void * dev, uint8_t reg_7_bit, uint32_t * commandresp );
+	int (*FlushLLCommands)( void * dev );
+	int (*DelayUS)( void * dev, int microseconds );
+
+	// Higher-level functions can be generated automatically.
+	int (*SetupInterface)( void * dev );
+	int (*Control3v3)( void * dev, int bOn );
+	int (*Control5v)( void * dev, int bOn );
+	int (*Unbrick)( void * dev ); // Turns on chip, erases everything, powers off.
+
+	int (*Exit)( void * dev );
+
+	int (*HaltMode)( void * dev, int one_if_halt_zero_if_resume );
+	int (*ConfigureNRSTAsGPIO)( void * dev, int one_if_yes_gpio );
+
+	// WARNING: Reading/writing must be at 32-bit boundaries for 32-bit sizes.
+	// WARNING: Writing binary blobs may write groups of 64-bytes.
+	int (*WriteBinaryBlob)( void * dev, uint32_t address_to_write, uint32_t blob_size, uint8_t * blob );
+	int (*ReadBinaryBlob)( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob );
+};
+
+
+#define DMDATA0        0x04
+#define DMDATA1        0x05
+#define DMCONTROL      0x10
+#define DMSTATUS       0x11
+#define DMHARTINFO     0x12
+#define DMABSTRACTCS   0x16
+#define DMCOMMAND      0x17
+#define DMABSTRACTAUTO 0x18
+#define DMPROGBUF0     0x20
+#define DMPROGBUF1     0x21
+#define DMPROGBUF2     0x22
+#define DMPROGBUF3     0x23
+#define DMPROGBUF4     0x24
+#define DMPROGBUF5     0x25
+#define DMPROGBUF6     0x26
+#define DMPROGBUF7     0x27
+
+#define CPBR       0x7C
+#define CFGR       0x7D
+#define SHDWCFGR   0x7E
+
+extern struct MiniChlinkFunctions MCF;
+
+// Returns 'dev' on success, else 0.
+void * TryInit_WCHLinkE();
+void * TryInit_ESP32S2CHFUN();
+
+// Returns 0 if ok, populated, 1 if not populated.
+int SetupAutomaticHighLevelFunctions();
+
+#endif
+
diff --git a/minichlink/pgm-esp32s2-ch32xx.c b/minichlink/pgm-esp32s2-ch32xx.c
new file mode 100644
index 0000000000000000000000000000000000000000..c51dcbb5a855c91021026475fa2df5ffe572596e
--- /dev/null
+++ b/minichlink/pgm-esp32s2-ch32xx.c
@@ -0,0 +1,167 @@
+#include <stdint.h>
+#include "hidapi.c"
+#include "minichlink.h"
+
+struct ESP32ProgrammerStruct
+{
+	hid_device * hd;
+	uint8_t commandbuffer[256];
+	int commandplace;
+	uint8_t reply[256];
+	int replylen;
+};
+
+int ESPFlushLLCommands( void * dev );
+
+static inline int SRemain( struct ESP32ProgrammerStruct * e )
+{
+	return sizeof( e->commandbuffer ) - e->commandplace - 1; //Need room for EOF.
+}
+
+static inline void Write4LE( struct ESP32ProgrammerStruct * e, uint32_t val )
+{
+	if( SRemain( e ) < 4 ) return;
+	uint8_t * d = e->commandbuffer + e->commandplace;
+	d[0] = val & 0xff;
+	d[1] = (val>>8) & 0xff;
+	d[2] = (val>>16) & 0xff;
+	d[3] = (val>>24) & 0xff;
+	e->commandplace += 4;
+}
+
+static inline void Write2LE( struct ESP32ProgrammerStruct * e, uint16_t val )
+{
+	if( SRemain( e ) < 2 ) return;
+	uint8_t * d = e->commandbuffer + e->commandplace;
+	d[0] = val & 0xff;
+	d[1] = (val>>8) & 0xff;
+	e->commandplace += 2;
+}
+
+static inline void Write1( struct ESP32ProgrammerStruct * e, uint8_t val )
+{
+	if( SRemain( e ) < 1 ) return;
+	uint8_t * d = e->commandbuffer + e->commandplace;
+	d[0] = val & 0xff;
+	e->commandplace ++;
+}
+
+
+static int ESPWriteReg32( void * dev, uint8_t reg_7_bit, uint32_t value )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+	if( SRemain( eps ) < 5 ) ESPFlushLLCommands( eps );
+
+	Write1( eps, (reg_7_bit<<1) | 1 );
+	Write4LE( eps, value );
+}
+
+int ESPReadReg32( void * dev, uint8_t reg_7_bit, uint32_t * commandresp )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+	if( SRemain( eps ) < 1 ) ESPFlushLLCommands( eps );
+
+	Write1( eps, (reg_7_bit<<1) | 0 );
+
+	int len = ESPFlushLLCommands( eps );
+
+	if( eps->replylen < 5 )
+	{
+		return -9;
+	}
+	else
+	{
+		memcpy( commandresp, eps->reply, 4 );
+		return 0;
+	}
+}
+
+int ESPFlushLLCommands( void * dev )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+
+	if( eps->commandplace >= sizeof( eps->commandbuffer ) )
+	{
+		fprintf( stderr, "Error: Command buffer overflow\n" );
+		return -5; 
+	}
+	eps->commandbuffer[0] = 0xad; // Key report ID
+	eps->commandbuffer[eps->commandplace] = 0xff;
+	int r = hid_send_feature_report( eps->hd, eps->commandbuffer, 255 );
+	eps->commandplace = 1;
+	if( r < 0 )
+	{
+		fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
+		return r;
+	}
+
+	eps->reply[0] = 0xad; // Key report ID
+	r = hid_get_feature_report( eps->hd, eps->reply, sizeof( eps->reply ) );
+printf( "RRLEN: %d\n", r );
+	if( r < 0 )
+	{
+		fprintf( stderr, "Error: Got error %d when sending hid feature report.\n", r );
+		return r;
+	}
+
+	eps->replylen = r;
+	return r;
+}
+	
+
+int ESPControl3v3( void * dev, int bOn )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+
+	if( SRemain( eps ) < 2 )
+		ESPFlushLLCommands( eps );
+
+	if( bOn )
+		Write2LE( eps, 0x03fe );
+	else
+		Write2LE( eps, 0x02fe );
+}
+
+int ESPDelayUS( void * dev, int microseconds )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+	if( SRemain( eps ) < 6 )
+		ESPFlushLLCommands( eps );
+
+	Write2LE( eps, 0x04fe );
+	Write4LE( eps, microseconds );
+}
+
+
+int ESPExit( void * dev )
+{
+	struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev;
+	hid_close( eps->hd );
+	free( eps );
+}
+
+void * TryInit_ESP32S2CHFUN()
+{
+	#define VID 0x303a
+	#define PID 0x4004
+	hid_init();
+	hid_device * hd = hid_open( VID, PID, L"s2-ch32xx-pgm-v0"); // third parameter is "serial"
+	if( !hd ) return 0;
+
+	struct ESP32ProgrammerStruct * eps = malloc( sizeof( struct ESP32ProgrammerStruct ) );
+	memset( eps, 0, sizeof( *eps ) );
+	eps->hd = hd;
+	eps->commandplace = 1;
+
+	memset( &MCF, 0, sizeof( MCF ) );
+	MCF.WriteReg32 = ESPWriteReg32;
+	MCF.ReadReg32 = ESPReadReg32;
+	MCF.FlushLLCommands = ESPFlushLLCommands;
+	MCF.DelayUS = ESPDelayUS;
+	MCF.Control3v3 = ESPControl3v3;
+	MCF.Exit = ESPExit;
+
+	return eps;
+}
+
+
diff --git a/minichlink/pgm-wch-linke.c b/minichlink/pgm-wch-linke.c
new file mode 100644
index 0000000000000000000000000000000000000000..a9d5b85ad2e78ba2af0132b883fdd10db2140eef
--- /dev/null
+++ b/minichlink/pgm-wch-linke.c
@@ -0,0 +1,357 @@
+// Tricky: You need to use wch link to use WCH-LinkRV.
+//  you can always uninstall it in device manager.  It will be under USB devices or something like that at the bottom.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include "libusb.h"
+#include "minichlink.h"
+
+#define WCHTIMEOUT 5000
+#define WCHCHECK(x) if( status = x ) { fprintf( stderr, "Bad USB Operation on " __FILE__ ":%d (%d)\n", __LINE__, status ); exit( status ); }
+
+const uint8_t * bootloader = (const uint8_t*)
+"\x21\x11\x22\xca\x26\xc8\x93\x77\x15\x00\x99\xcf\xb7\x06\x67\x45" \
+"\xb7\x27\x02\x40\x93\x86\x36\x12\x37\x97\xef\xcd\xd4\xc3\x13\x07" \
+"\xb7\x9a\xd8\xc3\xd4\xd3\xd8\xd3\x93\x77\x25\x00\x9d\xc7\xb7\x27" \
+"\x02\x40\x98\x4b\xad\x66\x37\x33\x00\x40\x13\x67\x47\x00\x98\xcb" \
+"\x98\x4b\x93\x86\xa6\xaa\x13\x67\x07\x04\x98\xcb\xd8\x47\x05\x8b" \
+"\x63\x16\x07\x10\x98\x4b\x6d\x9b\x98\xcb\x93\x77\x45\x00\xa9\xcb" \
+"\x93\x07\xf6\x03\x99\x83\x2e\xc0\x2d\x63\x81\x76\x3e\xc4\xb7\x32" \
+"\x00\x40\xb7\x27\x02\x40\x13\x03\xa3\xaa\xfd\x16\x98\x4b\xb7\x03" \
+"\x02\x00\x33\x67\x77\x00\x98\xcb\x02\x47\xd8\xcb\x98\x4b\x13\x67" \
+"\x07\x04\x98\xcb\xd8\x47\x05\x8b\x69\xe7\x98\x4b\x75\x8f\x98\xcb" \
+"\x02\x47\x13\x07\x07\x04\x3a\xc0\x22\x47\x7d\x17\x3a\xc4\x79\xf7" \
+"\x93\x77\x85\x00\xf1\xcf\x93\x07\xf6\x03\x2e\xc0\x99\x83\x37\x27" \
+"\x02\x40\x3e\xc4\x1c\x4b\xc1\x66\x2d\x63\xd5\x8f\x1c\xcb\x37\x07" \
+"\x00\x20\x13\x07\x07\x20\xb7\x27\x02\x40\xb7\x03\x08\x00\xb7\x32" \
+"\x00\x40\x13\x03\xa3\xaa\x94\x4b\xb3\xe6\x76\x00\x94\xcb\xd4\x47" \
+"\x85\x8a\xf5\xfe\x82\x46\xba\x84\x37\x04\x04\x00\x36\xc2\xc1\x46" \
+"\x36\xc6\x92\x46\x84\x40\x11\x07\x84\xc2\x94\x4b\xc1\x8e\x94\xcb" \
+"\xd4\x47\x85\x8a\xb1\xea\x92\x46\xba\x84\x91\x06\x36\xc2\xb2\x46" \
+"\xfd\x16\x36\xc6\xf9\xfe\x82\x46\xd4\xcb\x94\x4b\x93\xe6\x06\x04" \
+"\x94\xcb\xd4\x47\x85\x8a\x85\xee\xd4\x47\xc1\x8a\x85\xce\xd8\x47" \
+"\xb7\x06\xf3\xff\xfd\x16\x13\x67\x07\x01\xd8\xc7\x98\x4b\x21\x45" \
+"\x75\x8f\x98\xcb\x52\x44\xc2\x44\x61\x01\x02\x90\x23\x20\xd3\x00" \
+"\xf5\xb5\x23\xa0\x62\x00\x3d\xb7\x23\xa0\x62\x00\x55\xb7\x23\xa0" \
+"\x62\x00\xc1\xb7\x82\x46\x93\x86\x06\x04\x36\xc0\xa2\x46\xfd\x16" \
+"\x36\xc4\xb5\xf2\x98\x4b\xb7\x06\xf3\xff\xfd\x16\x75\x8f\x98\xcb" \
+"\x41\x89\x05\xcd\x2e\xc0\x0d\x06\x02\xc4\x09\x82\xb7\x07\x00\x20" \
+"\x32\xc6\x93\x87\x07\x20\x98\x43\x13\x86\x47\x00\xa2\x47\x82\x46" \
+"\x8a\x07\xb6\x97\x9c\x43\x63\x1c\xf7\x00\xa2\x47\x85\x07\x3e\xc4" \
+"\xa2\x46\x32\x47\xb2\x87\xe3\xe0\xe6\xfe\x01\x45\x61\xb7\x41\x45" \
+"\x51\xb7\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+
+int bootloader_len = 512;
+
+void wch_link_command( libusb_device_handle * devh, const uint8_t * command, int commandlen, int * transferred, uint8_t * reply, int replymax )
+{
+	uint8_t buffer[1024];
+	int got_to_recv = 0;
+	int status;
+	int transferred_local;
+	if( !transferred ) transferred = &transferred_local;
+	status = libusb_bulk_transfer( devh, 0x01, (char*)command, commandlen, transferred, WCHTIMEOUT );
+	if( status ) goto sendfail;
+
+	got_to_recv = 1;
+	if( !reply )
+	{
+		reply = buffer; replymax = sizeof( buffer );
+	}
+	
+	status = libusb_bulk_transfer( devh, 0x81, (char*)reply, replymax, transferred, WCHTIMEOUT );
+	if( status ) goto sendfail;
+	return;
+sendfail:
+	fprintf( stderr, "Error sending WCH command (%s): ", got_to_recv?"on recv":"on send" );
+	int i;
+	for( i = 0; i < commandlen; i++ )
+	{
+		printf( "%02x ", command[i] );
+	}
+	printf( "\n" );
+	exit( status );
+}
+
+static void wch_link_multicommands( libusb_device_handle * devh, int nrcommands, ... )
+{
+	int i;
+	va_list argp;
+	va_start(argp, nrcommands);
+	for( i = 0; i < nrcommands; i++ )
+	{
+		int clen = va_arg(argp, int);
+		wch_link_command( devh, va_arg(argp, char *), clen, 0, 0, 0 );
+	}
+	va_end( argp );
+}
+
+static inline libusb_device_handle * wch_link_base_setup( int inhibit_startup )
+{
+	libusb_context * ctx = 0;
+	int status;
+	status = libusb_init(&ctx);
+	if (status < 0) {
+		fprintf( stderr, "Error: libusb_init_context() returned %d\n", status );
+		exit( status );
+	}
+	
+	libusb_device **list;
+	libusb_device *found = NULL;
+	ssize_t cnt = libusb_get_device_list(ctx, &list);
+	ssize_t i = 0;
+	int err = 0;
+	for (i = 0; i < cnt; i++) {
+		libusb_device *device = list[i];
+		struct libusb_device_descriptor desc;
+		int r = libusb_get_device_descriptor(device,&desc);
+		if( r == 0 && desc.idVendor == 0x1a86 && desc.idProduct == 0x8010 ) { found = device; }
+	}
+
+	if( !found )
+	{
+		return 0;
+	}
+
+	libusb_device_handle * devh;
+	status = libusb_open( found, &devh );
+	if( status )
+	{
+		fprintf( stderr, "Error: couldn't open wch link device (libusb_open() = %d)\n", status );
+		return 0;
+	}
+		
+	WCHCHECK( libusb_claim_interface(devh, 0) );
+	
+	uint8_t rbuff[1024];
+	int transferred;
+	libusb_bulk_transfer( devh, 0x81, rbuff, 1024, &transferred, 1 ); // Clear out any pending transfers.  Don't wait though.
+
+	return devh;
+}
+
+static int LESetupInterface( void * dev )
+{
+	uint8_t rbuff[1024];
+	uint32_t transferred = 0;
+
+	// Place part into reset.
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x01", 4, &transferred, rbuff, 1024 );	// Reply is: "\x82\x0d\x04\x02\x08\x02\x00"
+
+	// TODO: What in the world is this?  It doesn't appear to be needed.
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x0c\x02\x09\x01", 5, 0, 0, 0 ); //Reply is: 820c0101
+
+	// This puts the processor on hold to allow the debugger to run.
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x02", 4, 0, 0, 0 ); // Reply: Ignored, 820d050900300500
+
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x11\x01\x09", 4, &transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
+	if( transferred != 20 )
+	{
+		fprintf( stderr, "Error: could not get part status\n" );
+		return -1;
+	}
+	fprintf( stderr, "Part Type (A): 0x%02x%02x (This is the capacity code, in KB)\n", rbuff[2], rbuff[3] );  // Is this Flash size?
+	fprintf( stderr, "Part UUID    : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", rbuff[4], rbuff[5], rbuff[6], rbuff[7], rbuff[8], rbuff[9], rbuff[10], rbuff[11] );
+	fprintf( stderr, "PFlags       : %02x-%02x-%02x-%02x\n", rbuff[12], rbuff[13], rbuff[14], rbuff[15] );
+	fprintf( stderr, "Part Type (B): %02x-%02x-%02x-%02x\n", rbuff[16], rbuff[17], rbuff[18], rbuff[19] );
+	return 0;
+}
+
+static int LEControl3v3( void * dev, int bOn )
+{
+	if( bOn )
+		wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x09", 4, 0, 0, 0 );
+	else
+		wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x09", 4, 0, 0, 0 );
+	return 0;
+}
+
+static int LEControl5v( void * dev, int bOn )
+{
+	if( bOn )
+		wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x0b", 4, 0, 0, 0 );
+	else
+		wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x0c", 4, 0, 0, 0 );
+	return 0;
+}
+
+static int LEUnbrick( void * dev )
+{
+	 wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\x0f\x09", 5, 0, 0, 0 );
+}
+
+static int LEHaltMode( void * dev, int one_if_halt_zero_if_resume )
+{
+	if( one_if_halt_zero_if_resume )
+	{
+		// Part one "immediately" places the part into reset.  Part 2 says when we're done, leave part in reset.
+		wch_link_multicommands( (libusb_device_handle *)dev, 2, 4, "\x81\x0d\x01\x02", 4, "\x81\x0d\x01\x01" );
+	}
+	else
+	{
+		// This is clearly not the "best" method to exit reset.  I don't know why this combination works.
+		wch_link_multicommands( (libusb_device_handle *)dev, 3, 4, "\x81\x0b\x01\x01", 4, "\x81\x0d\x01\x02", 4, "\x81\x0d\x01\xff" );
+	}
+}
+
+static int LEConfigureNRSTAsGPIO( void * dev, int one_if_yes_gpio )
+{
+	if( one_if_yes_gpio )
+	{
+		wch_link_multicommands( (libusb_device_handle *)dev, 2, 11, "\x81\x06\x08\x02\xff\xff\xff\xff\xff\xff\xff", 4, "\x81\x0b\x01\x01" );
+	}
+	else
+	{
+		wch_link_multicommands( (libusb_device_handle *)dev, 2, 11, "\x81\x06\x08\x02\xf7\xff\xff\xff\xff\xff\xff", 4, "\x81\x0b\x01\x01" );
+	}
+}
+
+static int LEReadBinaryBlob( void * dev, uint32_t offset, uint32_t amount, uint8_t * readbuff )
+{
+	int i;
+	int status;
+	uint8_t rbuff[1024];
+	int transferred = 0;
+	int readbuffplace = 0;
+
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 );
+
+	// Flush out any pending data.
+	libusb_bulk_transfer( (libusb_device_handle *)dev, 0x82, rbuff, 1024, &transferred, 1 );
+
+	// 3/8 = Read Memory
+	// First 4 bytes are big-endian location.
+	// Next 4 bytes are big-endian amount.
+	uint8_t readop[11] = { 0x81, 0x03, 0x08, };
+	
+	readop[3] = (offset>>24)&0xff;
+	readop[4] = (offset>>16)&0xff;
+	readop[5] = (offset>>8)&0xff;
+	readop[6] = (offset>>0)&0xff;
+
+	readop[7] = (amount>>24)&0xff;
+	readop[8] = (amount>>16)&0xff;
+	readop[9] = (amount>>8)&0xff;
+	readop[10] = (amount>>0)&0xff;
+	
+	wch_link_command( (libusb_device_handle *)dev, readop, 11, 0, 0, 0 );
+
+	// Perform operation
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x0c", 4, 0, 0, 0 );
+
+	uint32_t remain = amount;
+	while( remain )
+	{
+		transferred = 0;
+		WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x82, rbuff, 1024, &transferred, WCHTIMEOUT ) );
+		memcpy( ((uint8_t*)readbuff) + readbuffplace, rbuff, transferred );
+		readbuffplace += transferred;
+		remain -= transferred;
+	}
+
+	// Flip internal endian.  Must be done separately in case something was unaligned when
+	// reading.
+	for( i = 0; i < readbuffplace/4; i++ )
+	{
+		uint32_t r = ((uint32_t*)readbuff)[i];
+		((uint32_t*)readbuff)[i] = (r>>24) | ((r & 0xff0000) >> 8) | ((r & 0xff00)<<8) | (( r & 0xff )<<24); 
+	}
+
+	return 0;
+}
+
+static int LEWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t len, uint8_t * blob )
+{
+	int i;
+	int status;
+	uint8_t rbuff[1024];
+	int transferred;
+
+	int padlen = ((len-1) & (~0x3f)) + 0x40;
+
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 );
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x06\x01\x01", 4, 0, 0, 0 ); // Not sure why but it seems to work better when we request twice.
+
+	// This contains the write data quantity, in bytes.  (The last 2 octets)
+	// Then it just rollllls on in.
+	char rksbuff[11] = { 0x81, 0x01, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	rksbuff[9] = len >> 8;
+	rksbuff[10] = len & 0xff;
+	wch_link_command( (libusb_device_handle *)dev, rksbuff, 11, 0, 0, 0 );
+	
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x05", 4, 0, 0, 0 );
+	
+	int pplace = 0;
+	for( pplace = 0; pplace < bootloader_len; pplace += 64 )
+	{
+		WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, (uint8_t*)(bootloader+pplace), 64, &transferred, WCHTIMEOUT ) );
+	}
+	
+	for( i = 0; i < 10; i++ )
+	{
+		wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x07", 4, &transferred, rbuff, 1024 );
+		if( transferred == 4 && rbuff[0] == 0x82 && rbuff[1] == 0x02 && rbuff[2] == 0x01 && rbuff[3] == 0x07 )
+		{
+			break;
+		}
+	} 
+	if( i == 10 )
+	{
+		fprintf( stderr, "Error, confusing respones to 02/01/07\n" );
+		exit( -109 );
+	}
+	
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x02\x01\x02", 4, 0, 0, 0 );
+
+	for( pplace = 0; pplace < padlen; pplace += 64 )
+	{
+		if( pplace + 64 > len )
+		{
+			uint8_t paddeddata[64];
+			int gap = pplace + 64 - len;
+			int okcopy = len - pplace;
+			memcpy( paddeddata, blob + pplace, okcopy );
+			memset( paddeddata + okcopy, 0xff, gap );
+			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, paddeddata, 64, &transferred, WCHTIMEOUT ) );
+		}
+		else
+		{
+			WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, 64, &transferred, WCHTIMEOUT ) );
+		}
+	}
+	return 0;
+}
+
+int LEExit( void * dev )
+{
+	wch_link_command( (libusb_device_handle *)dev, "\x81\x0d\x01\xff", 4, 0, 0, 0);
+}
+
+void * TryInit_WCHLinkE()
+{
+	libusb_device_handle * wch_linke_devh;
+	wch_linke_devh = wch_link_base_setup(0);
+	if( !wch_linke_devh ) return 0;
+
+	MCF.WriteReg32 = 0;
+	MCF.ReadReg32 = 0;
+
+	MCF.SetupInterface = LESetupInterface;
+	MCF.Control3v3 = LEControl3v3;
+	MCF.Control5v = LEControl5v;
+	MCF.Unbrick = LEUnbrick;
+	MCF.HaltMode = LEHaltMode;
+	MCF.ConfigureNRSTAsGPIO = LEConfigureNRSTAsGPIO;
+	MCF.WriteBinaryBlob = LEWriteBinaryBlob;
+	MCF.ReadBinaryBlob = LEReadBinaryBlob;
+	MCF.Exit = LEExit;
+	return wch_linke_devh;
+};
+
+
+
diff --git a/minichlink/test.bat b/minichlink/test.bat
index 3a5e3aef7c0436edab07902076db66d3b93af317..863c041790e3ec6932dcad986e13b9d7aeeafa1f 100644
--- a/minichlink/test.bat
+++ b/minichlink/test.bat
@@ -1,10 +1 @@
-
-
-rem tcc wch_erase.c libusb-1.0.dll
-rem tcc wch_reset.c libusb-1.0.dll
-rem tcc wch_write_simple.c libusb-1.0.dll
-tcc minichlink.c libusb-1.0.dll
-rem tcc wch_dump_flash.c libusb-1.0.dll
-rem wch_erase.exe
-rem wch_write_simple.exe ..\barebones\barebones.bin
-rem wch_reset.exe
+tcc -lsetupapi minichlink.c libusb-1.0.dll pgm-esp32s2-ch32xx.c  pgm-wch-linke.c
diff --git a/minichlink/wch_link_base.h b/minichlink/wch_link_base.h
deleted file mode 100644
index 517924eab8f134eae7ad4579aaa001feaf8d245b..0000000000000000000000000000000000000000
--- a/minichlink/wch_link_base.h
+++ /dev/null
@@ -1,129 +0,0 @@
-// Tricky: You need to use wch link to use WCH-LinkRV.
-//  you can always uninstall it in device manager.  It will be under USB devices or something like that at the bottom.
-#ifndef _WCH_LINK_BASE_H
-#define _WCH_LINK_BASE_H
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include "libusb.h"
-
-#define WCHTIMEOUT 5000
-#define WCHCHECK(x) if( status = x ) { fprintf( stderr, "Bad USB Operation on " __FILE__ ":%d (%d)\n", __LINE__, status ); exit( status ); }
-
-void wch_link_command( libusb_device_handle * devh, const uint8_t * command, int commandlen, int * transferred, uint8_t * reply, int replymax )
-{
-	uint8_t buffer[1024];
-	int got_to_recv = 0;
-	int status;
-	int transferred_local;
-	if( !transferred ) transferred = &transferred_local;
-	status = libusb_bulk_transfer( devh, 0x01, (char*)command, commandlen, transferred, WCHTIMEOUT );
-	if( status ) goto sendfail;
-
-	got_to_recv = 1;
-	if( !reply )
-	{
-		reply = buffer; replymax = sizeof( buffer );
-	}
-	
-	status = libusb_bulk_transfer( devh, 0x81, (char*)reply, replymax, transferred, WCHTIMEOUT );
-	if( status ) goto sendfail;
-	return;
-sendfail:
-	fprintf( stderr, "Error sending WCH command (%s): ", got_to_recv?"on recv":"on send" );
-	int i;
-	for( i = 0; i < commandlen; i++ )
-	{
-		printf( "%02x ", command[i] );
-	}
-	printf( "\n" );
-	exit( status );
-}
-
-static void wch_link_multicommands( libusb_device_handle * devh, int nrcommands, ... )
-{
-	int i;
-	va_list argp;
-	va_start(argp, nrcommands);
-	for( i = 0; i < nrcommands; i++ )
-	{
-		int clen = va_arg(argp, int);
-		wch_link_command( devh, va_arg(argp, char *), clen, 0, 0, 0 );
-	}
-	va_end( argp );
-}
-
-static inline libusb_device_handle * wch_link_base_setup( int inhibit_startup )
-{
-	libusb_context * ctx = 0;
-	int status;
-	status = libusb_init(&ctx);
-	if (status < 0) {
-		fprintf( stderr, "Error: libusb_init_context() returned %d\n", status );
-		exit( status );
-	}
-	
-	libusb_device **list;
-	libusb_device *found = NULL;
-	ssize_t cnt = libusb_get_device_list(ctx, &list);
-	ssize_t i = 0;
-	int err = 0;
-	for (i = 0; i < cnt; i++) {
-		libusb_device *device = list[i];
-		struct libusb_device_descriptor desc;
-		int r = libusb_get_device_descriptor(device,&desc);
-		if( r == 0 && desc.idVendor == 0x1a86 && desc.idProduct == 0x8010 ) { found = device; }
-	}
-
-	if( !found )
-	{
-		fprintf( stderr, "Error: couldn't find wch link device\n" );
-		exit( -9 );
-	}
-
-	libusb_device_handle * devh;
-	status = libusb_open( found, &devh );
-	if( status )
-	{
-		fprintf( stderr, "Error: couldn't open wch link device (libusb_open() = %d)\n", status );
-		exit( -9 );
-	}
-		
-	WCHCHECK( libusb_claim_interface(devh, 0) );
-	
-	uint8_t rbuff[1024];
-	int transferred;
-	libusb_bulk_transfer( devh, 0x81, rbuff, 1024, &transferred, 1 ); // Clear out any pending transfers.  Don't wait though.
-
-
-	if( !inhibit_startup )
-	{
-		// Place part into reset.
-		wch_link_command( devh, "\x81\x0d\x01\x01", 4, &transferred, rbuff, 1024 );	// Reply is: "\x82\x0d\x04\x02\x08\x02\x00"
-
-		// TODO: What in the world is this?  It doesn't appear to be needed.
-		wch_link_command( devh, "\x81\x0c\x02\x09\x01", 5, 0, 0, 0 ); //Reply is: 820c0101
-
-		// This puts the processor on hold to allow the debugger to run.
-		wch_link_command( devh, "\x81\x0d\x01\x02", 4, 0, 0, 0 ); // Reply: Ignored, 820d050900300500
-
-		wch_link_command( devh, "\x81\x11\x01\x09", 4, &transferred, rbuff, 1024 ); // Reply: Chip ID + Other data (see below)
-		if( transferred != 20 )
-		{
-			fprintf( stderr, "Error: could not get part status\n" );
-			exit( -99 );
-		}
-		fprintf( stderr, "Part Type (A): 0x%02x%02x (This is the capacity code, in KB)\n", rbuff[2], rbuff[3] );  // Is this Flash size?
-		fprintf( stderr, "Part UUID    : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", rbuff[4], rbuff[5], rbuff[6], rbuff[7], rbuff[8], rbuff[9], rbuff[10], rbuff[11] );
-		fprintf( stderr, "PFlags       : %02x-%02x-%02x-%02x\n", rbuff[12], rbuff[13], rbuff[14], rbuff[15] );
-		fprintf( stderr, "Part Type (B): %02x-%02x-%02x-%02x\n", rbuff[16], rbuff[17], rbuff[18], rbuff[19] );
-	}
-	//for( i = 0; i < transferred; i++ )
-	//	printf( "%02x ", rbuff[i] );
-	//printf( "\n" );
-
-	return devh;
-}
-
-#endif
diff --git a/misc/README.md b/misc/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/misc/libgcc.a b/misc/libgcc.a
new file mode 100644
index 0000000000000000000000000000000000000000..7e3b7303b0bfcec86e4beccab77ede2ca3e753f6
Binary files /dev/null and b/misc/libgcc.a differ