Skip to content

Commit

Permalink
Added class UniqueIdBase
Browse files Browse the repository at this point in the history
  • Loading branch information
dc42 committed Oct 4, 2021
1 parent 922a68b commit 14571f6
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 0 deletions.
140 changes: 140 additions & 0 deletions src/UniqueIdBase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* UniqueIdBase.cpp
*
* Created on: 4 Oct 2021
* Author: David
*/

#include "UniqueIdBase.h"
#include <Cache.h>

#if SAM4E || SAM4S || SAME70
# include <Flash.h>
#endif

// Constructor initialises it to all zeros
void UniqueIdBase::Clear() noexcept
{
for (auto& v : data)
{
v = 0;
}
}

// Test if we have a valid ID. We assume a valid ID cannot be all zeros.
bool UniqueIdBase::IsValid() const noexcept
{
return (data[0] | data[1] | data[2] | data[3]) != 0;
}

// Get a 32-bit hash of the ID. Used for pseudo random number generation.
uint32_t UniqueIdBase::GetHash() const noexcept
{
return data[0] ^ data[1] ^ data[2] ^ data[3];
}

// Set the ID to the ID of the board that this code is running on
void UniqueIdBase::SetFromCurrentBoard() noexcept
{
#if SAME5x || SAMC21
for (size_t i = 0; i < 4; ++i)
{
data[i] = *reinterpret_cast<const uint32_t*>(SerialNumberAddresses[i]);
}
SetChecksumWord();
#elif SAM4E || SAM4S || SAME70
const bool cacheWasEnabled = Cache::Disable();
const bool success = Flash::ReadUniqueId(data);
if (cacheWasEnabled)
{
Cache::Enable();
}

if (success)
{
SetChecksumWord();
}
#else
# error Unsupported processor
#endif
}

// Set the ID from 4 dwords received from a remote board
void UniqueIdBase::SetFromRemote(const uint8_t srcData[16]) noexcept
{
memcpy(data, srcData, 16);
SetChecksumWord();
}

// Append the unique ID in character form to something
void UniqueIdBase::AppendCharsTo(function_ref<void(char) /*noexcept*/> fn) const noexcept
{
size_t i = 0;
for (;;)
{
const size_t index = (i * 5) / 32;
const size_t shift = (i * 5) % 32;
uint32_t val = data[index] >> shift;
if (shift > 32 - 5)
{
// We need some bits from the next dword too
val |= data[index + 1] << (32 - shift);
}
val &= 31;
char c;
if (val < 10)
{
c = val + '0';
}
else
{
c = val + ('A' - 10);
// We have 26 letters in the usual A-Z alphabet and we only need 22 of them plus 0-9.
// So avoid using letters C, E, I and O which are easily mistaken for G, F, 1 and 0.
if (c >= 'C')
{
++c;
}
if (c >= 'E')
{
++c;
}
if (c >= 'I')
{
++c;
}
if (c >= 'O')
{
++c;
}
}
fn(c);

++i;
if (i == 30)
{
break;
}

if ((i % 5) == 0)
{
fn('-');
}
}
}

// Append the unique ID in character form to a string
void UniqueIdBase::AppendCharsToString(const StringRef &str) const noexcept
{
AppendCharsTo([&str](char c)-> void { str.cat(c);});
}

// Set the checksum word of the unique ID
void UniqueIdBase::SetChecksumWord() noexcept
{
// We only print 30 5-bit characters = 128 data bits + 22 checksum bits. So compress the 32 checksum bits into 22.
data[4] = data[0] ^ data[1] ^ data[2] ^ data[3];
data[4] ^= (data[4] >> 10);
}

// End
43 changes: 43 additions & 0 deletions src/UniqueIdBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* UniqueIdBase.h
*
* Created on: 4 Oct 2021
* Author: David
*
* This class represents a 128-bit processor unique ID as implemented on ATSAM processors.
* We display the unique ID as a string in the form xxxxx-xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
* where each x is a digit or an uppercase letter that is not C, E, I or O.
* This encodes the original 128 bits plus 22 checksum bits.
*/

#ifndef SRC_UNIQUEIDBASE_H_
#define SRC_UNIQUEIDBASE_H_

#include <Core.h>
#include <General/StringRef.h>
#include <General/function_ref.h>

class UniqueIdBase
{
public:
UniqueIdBase() { Clear(); }

bool IsValid() const noexcept;
uint32_t GetHash() const noexcept;

void Clear() noexcept;
void SetFromCurrentBoard() noexcept;
void SetFromRemote(const uint8_t srcData[16]) noexcept;

void AppendCharsTo(function_ref<void(char) /*noexcept*/> fn) const noexcept;
void AppendCharsToString(const StringRef& str) const noexcept;

const uint8_t *GetRaw() const { return (const uint8_t*)data; }

protected:
void SetChecksumWord() noexcept;

uint32_t data[5];
};

#endif /* SRC_UNIQUEIDBASE_H_ */

0 comments on commit 14571f6

Please sign in to comment.