Skip to content

New way to create unique serial number#230

Merged
MobiFlight-Admin merged 10 commits intoMobiFlight:mainfrom
elral:UniqueID
Jan 6, 2023
Merged

New way to create unique serial number#230
MobiFlight-Admin merged 10 commits intoMobiFlight:mainfrom
elral:UniqueID

Conversation

@elral
Copy link
Collaborator

@elral elral commented Dec 28, 2022

@DocMoebiuz and @neilenns found a library with an undocumented feature to read an UniqueID on Atmega2560 and ATmega328. For new boards on first start up this UniqueID is used. In the library is also stated, that it might be possible that
two or more could have the same UniqueID (https://github.com/ricaun/ArduinoUniqueID/blob/master/MCU.md#Disclaimer).
My tests have shown that my megas have different UniqueID's.
But as this can not be excluded, generating a serial number as command from the connector is still available. In this case the random generator is used as before but the starting point are the milliseconds from starting up the board. It is very! unlikely to generate the serial number on exactly the same milliseconds between different boards, so a double serial number should not be generates anymore.

On startup of the board it is checked if a serial number was always generated. This is marked in the EEPROM with "SN" on the first two memory locations. In this case this serial number will still be used. Nothing changes for the user.

If a serial number is not available, it is checked if "ID" was written to the EEPROM. This means it is NOT the first start up and the UniqueID will be used as serial number.

If "SN" and "ID" is not read from the EEPROM, it is a first start up of the board an the UniqueID is used as serial number. This is also marked with writing "ID" to the first two EEPROM locations from the serial number locations.

If the user actively request a new serial number, a serial number according the existing style is generated and marked in the EEPROM with "SN". The starting point for the random generator is NOT anymore the analog input A0, it is the time difference from starting up the board until the command to generate a new serial (simply millis()).

In case a UniqueID is used, the serial number is longer than before. The array size for storing the serial number is calculated accordingly for the max. numbers of characters. The original definition MEM_LEN_SERIAL is kept, otherwise the device configuration would start at another position in the EEPROM.

Fixes #229

@elral elral requested a review from DocMoebiuz as a code owner December 28, 2022 06:24
@github-actions
Copy link

Firmware for this pull request:
Firmware.zip

@elral elral requested review from GioCC and neilenns December 28, 2022 06:29
#include "Button.h"
#include "Encoder.h"
#include "MFEEPROM.h"
#include "ArduinoUniqueID.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be included in mobiflight.cpp since UniqueId isn't used anywhere in the file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, that's an fragment from my testing.

src/Config.cpp Outdated
Comment on lines +448 to +474
if (!force && MFeeprom.read_byte(MEM_OFFSET_SERIAL) == 'I' && MFeeprom.read_byte(MEM_OFFSET_SERIAL + 1) == 'D') {
sprintf(serial, "SN-");
for (size_t i = 0; i < UniqueIDsize; i++) {
if (UniqueID[i] < 0x10) {
sprintf(&serial[3 + i * 2], "0%X", UniqueID[i]);
} else {
sprintf(&serial[3 + i * 2], "%X", UniqueID[i]);
}
}
return;
}

// Coming here it's the first start up of the board and no serial number or UniqueID is available
// Read the uniqueID and use it as serial numnber
if (!force) {
sprintf(serial, "SN-");
for (size_t i = 0; i < UniqueIDsize; i++) {
if (UniqueID[i] < 0x10) {
sprintf(&serial[3 + i * 2], "0%X", UniqueID[i]);
} else {
sprintf(&serial[3 + i * 2], "%X", UniqueID[i]);
}
}
// and mark this in the eeprom
MFeeprom.write_block(MEM_OFFSET_SERIAL, "ID", 2);
// Set first byte of config to 0x00 to ensure with empty config on 1st start up
MFeeprom.write_byte(MEM_OFFSET_CONFIG, 0x00);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only difference between these two blocks is whether the word "ID" gets written to eeprom. There's no real downside to writing "ID" every time this is called so this could be simplified significantly and an entire if statement could be removed.

Combined with my prior comment about force being tested first I believe that would simplify this function down to three cases:

  1. force is true
  2. SN is in eeprom so there's an old-style ID on the board
  3. all other cases

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me think about this. I will avoid writing to the EEPROM every time the board is started up (so just for reading the EEPROM).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the function can simplify down to something like this:

if (!force && legacy value stored)
{
    read legacy value;
    return;
}

read unique ID;

if (unique ID marker isn't stored)
{
   store ID marker in eeprom;
}

I'm pretty sure this covers all the cases. It will only write ID once, and will allow someone to "generate serial" from the desktop to get a new-style ID.

src/Config.cpp Outdated
if (!force && serial[0] == 'S' && serial[1] == 'N')
// A serial number according old style is already generated and saved to the eeprom
// So keep it to avoid a connector message with orphaned board
if (!force && MFeeprom.read_byte(MEM_OFFSET_SERIAL) == 'S' && MFeeprom.read_byte(MEM_OFFSET_SERIAL + 1) == 'N') {
Copy link
Contributor

@neilenns neilenns Dec 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the if statements in this method start with !force, which should get refactored out into a standalone if (force) test at the start of the function to do whatever force does (which as far as I can tell is nothing?). This will make for easier to follow function logic and simpler conditions on the rest of the if statements.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good hint!

@github-actions
Copy link

Firmware for this pull request:
Firmware.zip

@elral
Copy link
Collaborator Author

elral commented Dec 29, 2022

I still have to test the ProMicro and how to handle the UniqueID if it works (not listed as processor w/o UniqueID).

Copy link
Contributor

@neilenns neilenns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the updated version!

Copy link
Collaborator

@DocMoebiuz DocMoebiuz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice... this will hopefully help with this weird problem.

@github-actions
Copy link

github-actions bot commented Jan 5, 2023

Firmware for this pull request:
Firmware.zip

@github-actions
Copy link

github-actions bot commented Jan 6, 2023

Firmware for this pull request:
Firmware.zip

@MobiFlight-Admin MobiFlight-Admin merged commit a76c87a into MobiFlight:main Jan 6, 2023
@DocMoebiuz DocMoebiuz changed the title Unique New way to create unique serial number Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sometimes the same serial number gets generated

4 participants