0.1.1 UUID

This commit is contained in:
rob tillaart 2022-06-15 07:34:09 +02:00
parent a8bd32dc42
commit ef466db4c3
8 changed files with 176 additions and 45 deletions

View File

@ -13,73 +13,118 @@ Arduino library for generating UUID strings.
## Description
This experimental library provides a UUID generator.
This **experimental** library provides a UUID generator.
A UUID is an Universally Unique IDentifier of 128 bits.
These are typically written in the following format, defined in RFC 4122.
The basis for the UUID is a Marsaglia pseudo random number generator.
This must be seeded with two random numbers to get real usable UUID's.
```
0ac82d02-002b-4ccb-b96c-1c7839cbc4c0
^ ^
```
In such this is for experimental use only.
The length is 32 hexadecimal digits + four hyphens = 36 characters.
Note that the hexadecimal digits are lower case.
The 0.1.1 version of the lib tries to follow the RFC4122,
for version 4 (random generated) and variant 1.
In the format above the version 4 is indicated by the first arrow and must be 4.
The variant 1 is at the position of the second arrow.
This nibble must be 8,9, a or b.
All the remaining bits are random.
The basis for the UUID class is a Marsaglia pseudo random number generator.
This PRNG must be seeded with two real random uint32_t to get real random UUID's.
Often one sees also the term GUID = Globally Unique Identifier.
Tested on Arduino UNO only.
A UUID generated looks like 20d24650-d900-e34f-de49-8964ab3eb46d
- https://en.wikipedia.org/wiki/Universally_unique_identifier
- https://www.ietf.org/rfc/rfc4122.txt
## Interface
## UUID class
### UUID class
Use **\#include "UUID.h"**
- **UUID()** Constructor, initializes internals.
The UUID class has only a few methods.
- **UUID()** Constructor, initializes internals an generates a default UUID.
- **void seed(uint32_t s1, uint32_t s2 = 0)** reseeds the internal
pseudo random number generator.
Mandatory to set s1 while s2 is optional.
- **void generate()** generates a new UUID.
It is mandatory to set s1 while s2 is optional.
The combination {0, 0} is not allowed and overruled in software.
- **void generate()** generates a new UUID depending on the mode.
- **UUID_MODE_RANDOM**: all UUID bits are random.
- **UUID_MODE_VARIANT4**: the UUID (tries to) conform to version 4 variant 1. See above.
- **char \* toCharArray()** returns a pointer to a char buffer
representing the last generated UUID.
representing the last generated UUID.
Multiple subsequent calls to **toCharArray()** gives the same UUID
until **generate()** is called again.
### Mode
Only two modi are supported. Default is the **UUID_MODE_VARIANT4**.
- **void setVariant4Mode()** set mode to **UUID_MODE_VARIANT4**.
- **void setRandomMode()** set mode to **UUID_MODE_RANDOM**.
- **uint8_t getMode()** returns mode set.
### Printable
The UUID class implements the printable interface.
This allows one to print the UUID object directly.
To do so it uses the **toCharArray()** internally.
This allows one to print the UUID object directly over Serial and any other
stream implementing the Print interface. Think Ethernet or SD card.
```cpp
UUID uuid;
Serial.println(uuid);
// gives same output as
Serial.println(uuid.toCharArray());
```
Note: there is a known compile warning on AVR on this.
#### Performance
## Performance
Not tested ESP32 (and many other platforms) yet.
First numbers measured with **UUID_test.ino** shows the following timing.
Performance measured with **UUID_test.ino** shows the following times,
Note that 0.1.1 has substantial better performance on AVR.
| Version | Function | UNO 16 MHz | ESP32 240 MHz |
|:-------:|:-------------|:------------:|:---------------:|
| 0.1.0 | seed | 4 us | |
| 0.1.0 | generate | 412 us | |
| 0.1.0 | toCharArray | 4 us | |
| 0.1.1 | seed | 4 us | |
| 0.1.1 | generate | 248 us | |
| 0.1.1 | toCharArray | 4 us | |
The performance of **generate()** must be improved if possible.
UUID's per second
Note an UNO can generate 2000++ UUID's per second.
| Version | UNO 16 MHz | ESP32 240 MHz | notes |
|:-------:|:------------:|:---------------:|:------:|
| 0.1.0 | 2000++ | |
| 0.1.1 | 4000++ | | generate both modes
Note that this maximum is not realistic e.g. for a server where also
other tasks need to be done (listening, transfer etc).
## Operation
See examples.
Note: compile warning ...
## Future
@ -87,30 +132,39 @@ Note: compile warning ...
- improve documentation
- external random input needed
- GUID, UUID, versions (links)
- background
- rfc4122 layout
- background
- test other platforms
- investigate entropy harvesting
- freeRAM, micros, timers, RAM, USB-ID, ...
- GUID as derived class?
- (further identical?)
### Functions
- add **setSeparator(char)** and **getSeparator()** ?
- one char
- add **setUpperCase()** and **setLowerCase()**, **isUpperCase()**
- one bool flag
- binary output in a byte array
- **getBinary(uint8_t \* array)**
- need to store them from generate.
### Examples
- ESP32 UUID server
- using timing of the calls as entropy !
- RTC for entropy
- EEPROM to store last seeds?
### Fixes / optimizations
- improve performance of **generate()**
- reduce footprint
- can the buffer be reduced?
- smaller random generator?
### Won't
- support for { and }
- add **setSeparator(char)** and **getSeparator()** ?
- minus is the specification.

View File

@ -5,10 +5,16 @@
// DATE: 2022-06-14
// PURPOSE: Arduino Library for generating UUID's
// URL: https://github.com/RobTillaart/UUID
// https://en.wikipedia.org/wiki/UUID
// https://en.wikipedia.org/wiki/Universally_unique_identifier
//
// HISTORY
// 0.1.0 2022-06-14 initial version
// 0.1.1 2022-06-15 improve performance generate()
// minor edits in readme.md
// fix bug in generator
// define UUID_MODE_VARIANT4
// define UUID_MODE_RANDOM
#include "UUID.h"
@ -17,6 +23,7 @@
UUID::UUID()
{
seed(1, 2);
setVariant4Mode();
generate();
}
@ -38,20 +45,32 @@ void UUID::generate()
{
_ar[i] = _random();
}
// TODO improve efficiency
for (int i = 0, j = 0; i < 32; i++, j++)
// patch bits for version 1 and variant 4 here
if (_mode == UUID_MODE_VARIANT4)
{
if (i == 8) _buffer[j++] = '-';
if (i == 12) _buffer[j++] = '-';
if (i == 16) _buffer[j++] = '-';
if (i == 20) _buffer[j++] = '-';
_ar[1] &= 0xFFF0FFFF; // remove 4 bits.
_ar[1] |= 0x00040000; // variant 4
_ar[2] &= 0xFFFFFFF3; // remove 2 bits
_ar[2] |= 0x00000008; // version 1
}
// store globally ?
// build up the char array.
for (uint8_t i = 0, j = 0; i < 32; i++, j++)
{
if (i == 8) _buffer[j++] = '-';
else if (i == 12) _buffer[j++] = '-';
else if (i == 16) _buffer[j++] = '-';
else if (i == 20) _buffer[j++] = '-';
uint8_t nr = i / 8;
uint8_t shft = ((i % 8) * 4);
uint8_t ch = (_ar[nr] >> shft ) & 0xF;
uint8_t ch = _ar[nr] & 0xF;
_ar[nr] >>= 4;
_buffer[j] = (ch < 10) ? '0' + ch : 'a' - 10 + ch;
_buffer[j] = (ch < 10) ? '0' + ch : ('a' - 10) + ch;
}
_buffer[36] = 0;
}

View File

@ -2,20 +2,24 @@
//
// FILE: UUID.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// VERSION: 0.1.1
// DATE: 2022-06-14
// PURPOSE: Arduino Library for generating UUID's
// URL: https://github.com/RobTillaart/UUID
// https://en.wikipedia.org/wiki/UUID
// https://en.wikipedia.org/wiki/Universally_unique_identifier
//
// e.g. 20D24650-D900-E34F-DE49-8964AB3EB46D
// e.g. 20d24650-d900-e34f-de49-8964ab3eb46d
#include "Arduino.h"
#include "Printable.h"
#define UUID_LIB_VERSION (F("0.1.0"))
#define UUID_LIB_VERSION (F("0.1.1"))
// TODO an enum?
#define UUID_MODE_VARIANT4 0
#define UUID_MODE_RANDOM 1
/////////////////////////////////////////////////
@ -34,6 +38,10 @@ public:
// make a UUID string
char * toCharArray();
void setVariant4Mode() { _mode = UUID_MODE_VARIANT4; };
void setRandomMode() { _mode = UUID_MODE_RANDOM; };
uint8_t getMode() { return _mode; };
// Printable interface
size_t printTo(Print& p) const;
@ -46,6 +54,7 @@ private:
// UUID in string format
char _buffer[37];
uint8_t _mode = UUID_MODE_VARIANT4;
};

View File

@ -19,13 +19,26 @@ void setup()
Serial.println(UUID_LIB_VERSION);
uint16_t count = 0;
uuid.setVariant4Mode();
uint32_t start = millis();
while (millis() - start < 1000)
{
uuid.generate();
count++;
}
Serial.print("Generated ");
Serial.print("Generate 4: ");
Serial.print(count);
Serial.println(" uuid's per second.");
count = 0;
uuid.setRandomMode();
start = millis();
while (millis() - start < 1000)
{
uuid.generate();
count++;
}
Serial.print("Generate R: ");
Serial.print(count);
Serial.println(" uuid's per second.");
}

View File

@ -9,8 +9,15 @@ seed KEYWORD2
generate KEYWORD2
toCharArray KEYWORD2
setVariant4Mode KEYWORD2
setRandomMode KEYWORD2
getMode KEYWORD2
# Constants (LITERAL1)
UUID_LIB_VERSION LITERAL1
UUID_MODE_RANDOM LITERAL1
UUID_MODE_VARIANT4 LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/UUID.git"
},
"version": "0.1.0",
"version": "0.1.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=UUID
version=0.1.0
version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for generating UUID's. (experimental).

View File

@ -38,6 +38,13 @@ unittest_teardown()
}
unittest(test_constants)
{
assertEqual(0, UUID_MODE_VARIANT4);
assertEqual(1, UUID_MODE_RANDOM);
}
unittest(test_generate)
{
UUID uuid;
@ -77,11 +84,33 @@ unittest(test_layout)
assertEqual('-', u[8]);
assertEqual('-', u[13]);
assertEqual('4', u[15]);
assertEqual('-', u[18]);
assertEqual('-', u[23]);
}
unittest(test_mode)
{
UUID uuid;
assertEqual(UUID_MODE_VARIANT4, uuid.getMode());
uuid.setRandomMode();
assertEqual(UUID_MODE_RANDOM, uuid.getMode());
uuid.setVariant4Mode();
assertEqual(UUID_MODE_VARIANT4, uuid.getMode());
}
unittest(test_printTo)
{
UUID uuid;
assertEqual(36, Serial.print(uuid)); // 36
assertEqual(38, Serial.println(uuid)); // 36 + \n\r
}
unittest_main()