/**
* Copyright (c) 2022 - James Owens <jjo(at)arduando.com.br>
*
* Arquivo: _005_Save2EEPROM.ino
* Arquivo: 18/12/2022 12:31:03
* Versão:
* Fonte:
* Website: https://arduando.com.br
*
* Descrição:
*
* DISCLAIMER:
* The author is in no way responsible for any problems or damage caused by
* using this code. Use at your own risk.
*
* LICENSE:
* This code is distributed under the GNU Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
* More details can be found at http://www.gnu.org/licenses/gpl.txt
*/
#include <EEPROM.h>
/* Random number generation based on post
"1999-01-15 Jeff Stout" @ http://www.ciphersbyritter.com/NEWS4/RANDC.HTM
*/
#define UL unsigned long
#define znew ((z=36969*(z&65535)+(z>>16))<<16)
#define wnew ((w=18000*(w&65535)+(w>>16))&65535)
#define MWC (znew+wnew)
#define SHR3 (jsr=(jsr=(jsr=jsr^(jsr<<17))^(jsr>>13))^(jsr<<5))
#define CONG (jcong=69069*jcong+1234567)
#define KISS ((MWC^CONG)+SHR3)
// Global static variables: the seed changes on every minute)/
UL z, w, jsr, jcong;
uint32_t seed;
#define EEPROM_SIGNATURE "~jbit.com.br"
#define EEPROM_SIGNATURE_LENGTH 11
#define KEY_ADDRESS_MAP_START EEPROM_SIGNATURE_LENGTH+1
#define NUMBER_OF_KEYS 7
uint8_t keyAddrMap[4];
#define SECURITY_KEY_APPEUI 0
#define SECURITY_KEY_DEVEUI 1
#define SECURITY_KEY_APPKEY 2
#define SECURITY_KEY_NETID 3
#define SECURITY_KEY_DEVADDR 4
#define SECURITY_KEY_ARTKEY 5
#define SECURITY_KEY_NWKEY 6
const uint8_t securityKeys[] = {16, 8, 8, 1, 4, 16, 16};
//////
// The order
// 00 AppEUI (16)
// 01 DevEUI (8)
// 02 AppKey (8)
// 03 netId (1)
// 04 devAddr (4)
// 05 artKey (16)
// 06 nwKey (16)
void securityKeyHandler(uint8_t _keyName, uint8_t *_keyValue, char _operation)
{
uint8_t i=0;
uint8_t tempByte;
bool isHighByte = true;
uint8_t keyAddressOffset=0;
// There can be only 7, anything else is in error, minimum attempt to validate it
if (_keyName < 0x07)
{
Serial.println();
do{
tempByte = EEPROM.read(KEY_ADDRESS_MAP_START+i);
if (isHighByte)
{
if ((tempByte >> 4) == _keyName)
break;
keyAddressOffset += securityKeys[tempByte>>4];
isHighByte = false;
}
if (!isHighByte)
{
if ((tempByte & 0x0F) == _keyName)
break;
keyAddressOffset += securityKeys[tempByte&0x0F];
isHighByte = true;
}
i++;
} while (i < ((NUMBER_OF_KEYS / 2) + (NUMBER_OF_KEYS % 2)));
// Store the requested key in the buffer provided in the argument
for (i = 0; i < securityKeys[_keyName]; i++)
{
if (_operation == 'r')
_keyValue[i] = EEPROM.read(KEY_ADDRESS_MAP_START + NUMBER_OF_KEYS/2 + NUMBER_OF_KEYS%2 + keyAddressOffset + i);
if (_operation == 'w')
EEPROM.write(KEY_ADDRESS_MAP_START + NUMBER_OF_KEYS/2 + NUMBER_OF_KEYS%2 + keyAddressOffset + i, _keyValue[i]);
}
}
}
void setSecurityKey(uint8_t _keyName, uint8_t *_keyValue)
{
securityKeyHandler (_keyName, _keyValue, 'w');
}
void getSecurityKey(uint8_t _keyName, uint8_t *_keyValue)
{
securityKeyHandler (_keyName, _keyValue, 'r');
}
void setup()
{
char keyValue[16];
Serial.begin(115200);
while (!Serial);
eeSaveSignature();
setKeyAddrMap();
//keyValue = "Test";
setSecurityKey(SECURITY_KEY_APPKEY, &keyValue[0]);
dumpEEPROM();
for (uint8_t i=0; i<NUMBER_OF_KEYS; i++)
{
getSecurityKey(i, &keyValue[0]);
for (int j=0; j<securityKeys[i]; j++)
{
Serial.print(keyValue[j], HEX);
Serial.print(" ");
}
}
}
void loop()
{
}
void eeSaveSignature(void)
{
// Initialize the first 255 EEPROM addresses
// sequentially with values from 0 to 254
for (int i=0; i<255; i++)
EEPROM.write(i, i);
EEPROM.put(0, EEPROM_SIGNATURE);
}
void setKeyAddrMap(void)
{
uint8_t foundIndex = 0;
bool foundIndexHighNibble = true;
bool exists = false;
uint8_t keyIndex = 0;
bool keyIndexHighNibble = true;
uint8_t sequence[NUMBER_OF_KEYS];
for (uint8_t i = 0; i < strlen(__TIMESTAMP__); i++)
{
seed += __TIMESTAMP__[i];
}
// Set global variables used in the random number generator algorithm
z = 362436069 * (int)seed, w = 521288629 * (int)seed, jsr = 123456789 * (int)seed, jcong = 380116160 * (int)seed;
uint8_t digit;
do
{
digit = KISS & 0xF;
//Serial.print (digit , HEX);
exists = false;
if (digit >= 0 && digit < NUMBER_OF_KEYS)
{
for (uint8_t i = 0; i < foundIndex; i++)
{
if (sequence[i] == digit)
exists = true;
}
if (exists == false)
{
sequence[foundIndex] = digit;
foundIndex++;
}
}
} while (foundIndex < NUMBER_OF_KEYS);
for (int i = 0, j = 0; j < (NUMBER_OF_KEYS / 2) + (NUMBER_OF_KEYS % 2); i += 2, j++)
{
keyAddrMap[j] = (sequence[i] << 4);
if (NUMBER_OF_KEYS % 2 > 0)
{
if (i != (NUMBER_OF_KEYS - 1))
keyAddrMap[j] += sequence[i + 1];
}
else keyAddrMap[j] += sequence[i + 1];
EEPROM.write(KEY_ADDRESS_MAP_START+j, keyAddrMap[j]);
Serial.print (keyAddrMap[j], HEX); Serial.print(" ");
}
delay(500);
Serial.println();
}
void dumpEEPROM()
{
int memIdx = 0; // Indice na memória EEPROM
int n = 0;
int tmp = 0;
int precision = 1; // Número de dígitos hex no endereço de memória
int addrLength = 0; // Total de bytes na memória EEPROM
int rows = 0; // Linha sendo processada nos resultados
char address[128]; // Buffer contendo o intervalo de memória nos resultados
char mask[16]; // Buffer com máscara de formatação do intervalo de memória
// Diferentes arquiteturas podem variar o tamanho da EEPROM. Obtenho o numero de bytes.
addrLength = EEPROM.length();
tmp = addrLength;
rows = addrLength / 16; // São 16 bytes mostrados por linha
// Cálculo do número de digitos hex no endereço, usado para formatação da saída
do {
tmp = tmp >> 4;
if (tmp > 0) precision++;
} while (tmp > 0);
sprintf(mask, "0x%%.%dX 0x%%.%dX ", precision, precision);
Serial.print("\nDescarregando conteúdo da EEPROM (");
Serial.print(addrLength);
Serial.print(" bytes):\n");
// Apresenta o conteúdo da memória EEPROM
for (int r = 0; r < rows; r++)
{
sprintf(address, mask, memIdx, memIdx + 0xF);
Serial.print(address);
for (n = 0; n < 16; n++)
{
if (EEPROM[memIdx + n] <= 0xF)
Serial.print("0");
Serial.print(EEPROM[memIdx + n], HEX);
if (n != 7)Serial.print(" ");
else Serial.print("-");
}
Serial.print(" ");
for (int n = 0; n < 16; n++)
{
// Mostra apenas caracteres válidos (entre ASCII 32 e 128)
if (EEPROM[memIdx + n] > 128 || EEPROM[memIdx + n] < 32) Serial.print(".");
else Serial.write(EEPROM[memIdx + n]);
}
memIdx += n;
Serial.print("\n");
}
Serial.print("fim!");
}