Чуть правленные исходники v3.11 1.11: изменен делитель тактирования spi + частота кварца для мастер станции

This commit is contained in:
2025-10-03 09:48:30 +03:00
parent df18fedc7f
commit 3f886d0f98
94 changed files with 19758 additions and 0 deletions
@@ -0,0 +1,17 @@
#ifndef SPORTIDUINO_DEBUG_H
#define SPORTIDUINO_DEBUG_H
#ifdef DEBUG
#define DEBUG_PRINTLN(x) Serial.println(x)
#define DEBUG_PRINT(x) Serial.print(x)
#define DEBUG_PRINTLN_FORMAT(x, format) Serial.println(x, format)
#define DEBUG_PRINT_FORMAT(x, format) Serial.print(x, format)
#else
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN_FORMAT(x, format)
#define DEBUG_PRINT_FORMAT(x, format)
#endif
#endif
@@ -0,0 +1,532 @@
#include <Arduino.h>
#include <SPI.h>
#include "debug.h"
#include "rfid.h"
void Rfid::init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain) {
rfidSsPin = ssPin;
rfidRstPin = rstPin;
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
memset(authPwd.pass, 0xFF, 4);
memset(authPwd.pack, 0, 2);
}
void Rfid::clearLastCardUid() {
memset(&lastCardUid, 0, sizeof(lastCardUid));
}
void Rfid::setAntennaGain(uint8_t newAntennaGain) {
antennaGain = constrain(newAntennaGain, MIN_ANTENNA_GAIN, MAX_ANTENNA_GAIN);
}
void Rfid::setAuthPassword(uint8_t* password) {
if(!password) {
return;
}
for (uint8_t i = 0; i < 4; i++) {
authPwd.pass[i] = password[i];
}
}
void Rfid::begin(uint8_t newAntennaGain) {
if(newAntennaGain) {
antennaGain = newAntennaGain;
}
cardType = CardType::UNKNOWN;
authenticated = false;
SPI.begin();
mfrc522.PCD_Init(rfidSsPin, rfidRstPin);
mfrc522.PCD_AntennaOff();
mfrc522.PCD_SetAntennaGain(antennaGain<<4);
mfrc522.PCD_AntennaOn();
delay(5);
if(!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
clearLastCardUid();
return;
}
auto piccType = MFRC522::PICC_GetType(mfrc522.uid.sak);
switch(piccType) {
case MFRC522::PICC_TYPE_MIFARE_MINI:
cardType = CardType::MIFARE_MINI;
return;
case MFRC522::PICC_TYPE_MIFARE_1K:
cardType = CardType::MIFARE_1K;
return;
case MFRC522::PICC_TYPE_MIFARE_4K:
cardType = CardType::MIFARE_4K;
return;
case MFRC522::PICC_TYPE_MIFARE_UL: {
byte pageData[18];
byte dataSize = sizeof(pageData);
if(ntagCard4PagesRead(3, pageData, &dataSize)) {
switch(pageData[2]) {
case 0x12:
cardType = CardType::NTAG213;
return;
case 0x3e:
cardType = CardType::NTAG215;
return;
case 0x6d:
cardType = CardType::NTAG216;
return;
}
}
}
default:
cardType = CardType::UNKNOWN;
return;
}
}
void Rfid::end() {
if(isCardDetected()) {
memcpy(&lastCardUid, &mfrc522.uid, sizeof(lastCardUid));
}
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
SPI.end();
digitalWrite(rfidRstPin, LOW);
}
bool Rfid::isCardDetected() {
if(cardType != CardType::UNKNOWN) {
return true;
}
return false;
}
bool Rfid::isNewCardDetected() {
if(isCardDetected()) {
for(uint8_t i = 0; i < mfrc522.uid.size; i++) {
if(lastCardUid.uidByte[i] != mfrc522.uid.uidByte[i]) {
return true;
}
}
DEBUG_PRINTLN("Same UID");
}
return false;
}
MFRC522::MIFARE_Key defaultMifareKey = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
bool Rfid::mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size) {
// data size should be at least 18 bytes!
if(pageAdr < 3 || *size < 18) {
return false;
}
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
byte trailerBlock = blockAddr + (3-blockAddr%4);
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
if(status != MFRC522::STATUS_OK) {
return false;
}
status = mfrc522.MIFARE_Read(blockAddr, data, size);
if(status != MFRC522::STATUS_OK) {
return false;
}
return true;
}
bool Rfid::mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size) {
// data size should be 16 bytes!
if(pageAdr < 3 || size < 16) {
return false;
}
byte blockAddr = pageAdr-3 + ((pageAdr-3)/3);
byte trailerBlock = blockAddr + (3-blockAddr%4);
auto status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &defaultMifareKey, &(mfrc522.uid));
if(status != MFRC522::STATUS_OK) {
return false;
}
status = mfrc522.MIFARE_Write(blockAddr, data, size);
if(status != MFRC522::STATUS_OK) {
return false;
}
return true;
}
bool Rfid::ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage) {
if(negAuthAttemptsLim > 7) {
negAuthAttemptsLim = 7;
}
uint8_t maxPage = getCardMaxPage();
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, password->pass, 4)) {
return false;
}
uint8_t packPageData[4] = {password->pack[0], password->pack[1], 0, 0};
if(!ntagCardPageWrite(maxPage + PAGE_PACK_OFFSET, packPageData, 4)) {
return false;
}
//uint8_t pageData[18];
//uint8_t dataSize = sizeof(pageData);
//if(!ntagCard4PagesRead(maxPage + PAGE_CFG1_OFFSET, pageData, &dataSize)) {
// return false;
//}
uint8_t accessByteData = readAndWrite ? 0x80 : 0x00;
accessByteData |= negAuthAttemptsLim & 0x07;
uint8_t cfg1PageData[4] = {accessByteData, 0, 0, 0};
if(!ntagCardPageWrite(maxPage + PAGE_CFG1_OFFSET, cfg1PageData, 4)) {
return false;
}
// Set start page to enable the password verification at the end of the procedure
uint8_t cfg0PageData[4] = {0, 0, 0, startPage};
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
return false;
}
return true;
}
bool Rfid::ntagDisableAuthentication() {
DEBUG_PRINTLN("ntagDisableAuthentication");
uint8_t maxPage = getCardMaxPage();
uint8_t defaultPassword[4] = {0xff, 0xff, 0xff, 0xff};
// Reset password
if(!ntagCardPageWrite(maxPage + PAGE_PWD_OFFSET, defaultPassword, 4)) {
return false;
}
uint8_t cfg0PageData[4] = {0, 0, 0, 0xff};
if(!ntagCardPageWrite(maxPage + PAGE_CFG0_OFFSET, cfg0PageData, 4)) {
return false;
}
return true;
}
bool Rfid::ntagAuth(NtagAuthPassword *password) {
if(!password) {
DEBUG_PRINTLN(F("ntagAuth password is null"));
return false;
}
if (!isCardDetected()) {
DEBUG_PRINTLN(F("ntagAuth card is not detected"));
return false;
}
#ifdef DEBUG
DEBUG_PRINTLN(F("Authenticating..."));
DEBUG_PRINT(F("Password: "));
for(uint8_t i = 0; i < 4; i++) {
DEBUG_PRINT_FORMAT(password->pass[i], HEX);
DEBUG_PRINT(F(" "));
}
DEBUG_PRINTLN("");
DEBUG_PRINT(F("Pack: "));
for(uint8_t i = 0; i < 2; i++) {
DEBUG_PRINT_FORMAT(password->pack[i], HEX);
DEBUG_PRINT(F(" "));
}
DEBUG_PRINTLN("");
#endif
uint8_t packReturn[2] = {0, 0};
auto status = (MFRC522::StatusCode)mfrc522.PCD_NTAG21x_Auth(&password->pass[0], packReturn);
DEBUG_PRINT(F("Pack from card: 0x"));
DEBUG_PRINT_FORMAT(packReturn[0], HEX);
DEBUG_PRINT(F(" 0x"));
DEBUG_PRINTLN_FORMAT(packReturn[1], HEX);
if(status != MFRC522::STATUS_OK) {
DEBUG_PRINT(F("Auth failed, status: 0x"));
DEBUG_PRINTLN_FORMAT(status, HEX);
if (status == MFRC522::STATUS_TIMEOUT) {
byte atqa_answer[2];
byte atqa_size = 2;
mfrc522.PICC_WakeupA(atqa_answer, &atqa_size);
if (!mfrc522.PICC_ReadCardSerial()) {
DEBUG_PRINTLN(F("ReadCardSerial failed"));
}
}
return false;
}
return true;
}
bool Rfid::ntagTryAuth(bool ignoreAuthError) {
if(authPwd.pass[0] != 0xFF || authPwd.pass[1] != 0xFF || authPwd.pass[2] != 0xFF || authPwd.pass[3] != 0xFF) {
if(!ntagAuth(&authPwd)) {
if(!ignoreAuthError) {
return false;
}
DEBUG_PRINTLN(F("ignore auth error"));
}
}
authenticated = true;
return true;
}
bool Rfid::ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError) {
if(*size < 18) {
return false;
}
if(pageAdr >= CARD_PAGE_INIT && !authenticated) {
if (!ntagTryAuth(ignoreAuthError)) {
return false;
}
}
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Read(pageAdr, data, size);
if(status != MFRC522::STATUS_OK) {
return false;
}
return true;
}
bool Rfid::ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError) {
DEBUG_PRINT(F("ntagCardPageWrite pageAdr: "));
DEBUG_PRINT(pageAdr);
DEBUG_PRINT(F(" size: "));
DEBUG_PRINTLN(size);
if(pageAdr < 2 || size < 4) {
return false;
}
if(!authenticated || !ignoreAuthError) {
if(!ntagTryAuth(ignoreAuthError)) {
return false;
}
}
auto status = (MFRC522::StatusCode)mfrc522.MIFARE_Ultralight_Write(pageAdr, data, size);
if(status != MFRC522::STATUS_OK) {
DEBUG_PRINT(F("ntagCardPageWrite failed, status: 0x"));
DEBUG_PRINTLN_FORMAT(status, HEX);
return false;
}
return true;
}
uint8_t Rfid::getCardMaxPage() {
switch(cardType) {
case CardType::MIFARE_MINI:
return 17;
case CardType::MIFARE_1K:
return 50;
case CardType::MIFARE_4K:
return 98;
case CardType::MIFARE_UL:
return 39;
case CardType::NTAG216:
return 225;
case CardType::NTAG215:
return 129;
case CardType::NTAG213:
return 39;
default:
return 0;
}
return 0;
}
CardType Rfid::getCardType() {
return cardType;
}
bool Rfid::cardPageRead(uint8_t pageAdr, byte *data, uint8_t size, bool ignoreAuthError) {
uint8_t maxPage = getCardMaxPage();
if(pageAdr > maxPage) {
return false;
}
bool result = false;
byte pageData[18];
byte dataSize = sizeof(pageData);
switch(cardType) {
case CardType::MIFARE_MINI:
case CardType::MIFARE_1K:
case CardType::MIFARE_4K:
result = mifareCardPageRead(pageAdr, pageData, &dataSize);
break;
case CardType::MIFARE_UL:
case CardType::NTAG213:
case CardType::NTAG215:
case CardType::NTAG216:
default:
result = ntagCard4PagesRead(pageAdr, pageData, &dataSize, ignoreAuthError);
break;
}
if(result) {
memcpy(data, pageData, size);
}
return result;
}
bool Rfid::cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size, bool ignoreAuthError) {
uint8_t maxPage = getCardMaxPage();
if(pageAdr > maxPage) {
return false;
}
byte pageData[16];
memset(pageData, 0, sizeof(pageData));
memcpy(pageData, data, size);
switch(cardType) {
case CardType::MIFARE_MINI:
case CardType::MIFARE_1K:
case CardType::MIFARE_4K:
return mifareCardPageWrite(pageAdr, pageData, sizeof(pageData));
case CardType::MIFARE_UL:
case CardType::NTAG213:
case CardType::NTAG215:
case CardType::NTAG216:
default:
return ntagCardPageWrite(pageAdr, pageData, sizeof(pageData), ignoreAuthError);
}
}
bool Rfid::cardPageWrite(uint8_t pageAdr, uint32_t value) {
byte data[4];
data[0] = (value >> 24) & 0xFF;
data[1] = (value >> 16) & 0xFF;
data[2] = (value >> 8) & 0xFF;
data[3] = value & 0xFF;
return cardPageWrite(pageAdr, data, 4);
}
bool Rfid::cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size) {
uint8_t pageAddr = startPageAdr;
for(uint8_t i = 0; i < size/4; ++i) {
if(!cardPageWrite(pageAddr++, data + i*4)) {
return false;
}
}
uint8_t tailSize = size%4;
if(tailSize > 0) {
if(!cardPageWrite(pageAddr, data + size - tailSize, tailSize)) {
return false;
}
}
return true;
}
bool Rfid::cardErase(uint8_t beginPageAddr, uint8_t endPageAddr) {
for(uint8_t pageAddr = endPageAddr; pageAddr >= beginPageAddr; --pageAddr) {
if(!cardPageErase(pageAddr)) {
return false;
}
}
return true;
}
bool Rfid::cardPageErase(uint8_t pageAddr) {
DEBUG_PRINT(F("Erasing page "));
DEBUG_PRINTLN(pageAddr);
byte pageData[4];
if(!cardPageRead(pageAddr, pageData)) {
return false;
}
for(uint8_t i = 0; i < 4; ++i) {
if(pageData[i] != 0) {
const byte emptyBlock[] = {0,0,0,0};
return cardPageWrite(pageAddr, emptyBlock);
}
}
return true;
}
bool Rfid::cardErase4Pages(uint8_t pageAddr) {
if (!isCardDetected()) {
return false;
}
switch(cardType) {
case CardType::MIFARE_MINI:
case CardType::MIFARE_1K:
case CardType::MIFARE_4K: {
for(uint8_t i = 0; i < 4; ++i) {
if(!cardPageErase(pageAddr + 3 - i)) {
return false;
}
}
return true;
}
case CardType::NTAG213:
case CardType::NTAG215:
case CardType::NTAG216: {
DEBUG_PRINT(F("Checking pages at "));
DEBUG_PRINTLN(pageAddr);
byte pageData[18];
byte dataSize = sizeof(pageData);
if(!ntagCard4PagesRead(pageAddr, pageData, &dataSize)) {
return false;
}
for(uint8_t i = 0; i < 4; ++i) {
for(uint8_t j = 0; j < 4; ++j) {
uint8_t offset = (3 - i);
if(pageData[offset*4 + j] != 0) {
const byte emptyBlock[] = {0,0,0,0};
if(!ntagCardPageWrite(pageAddr + offset, emptyBlock, sizeof(emptyBlock))) {
return false;
}
break;
}
}
}
return true;
}
default:
return false;
}
}
bool Rfid::cardEnableDisableAuthentication(bool writeProtection, bool readProtection) {
if (!isCardDetected()) {
return false;
}
switch(cardType) {
case CardType::MIFARE_MINI:
case CardType::MIFARE_1K:
case CardType::MIFARE_4K: {
// TODO: not implemented yet
return true;
}
case CardType::NTAG213:
case CardType::NTAG215:
case CardType::NTAG216: {
if(!writeProtection) {
return ntagDisableAuthentication();
}
// Enable authentication from page 4 and with unlimited negative password verification attempts
return ntagSetPassword(&authPwd, readProtection, 0, CARD_PAGE_INIT);
}
default:
return true;
}
}
@@ -0,0 +1,133 @@
#ifndef SPORTIDUINO_RFID_H
#define SPORTIDUINO_RFID_H
#include <MFRC522.h>
#define MIN_ANTENNA_GAIN 2
#define MAX_ANTENNA_GAIN 7
#define DEFAULT_ANTENNA_GAIN 4
#define CARD_PAGE_INIT 4
#define CARD_PAGE_INIT_TIME 5
#define CARD_PAGE_LAST_RECORD_INFO 6
#define CARD_PAGE_INFO1 6
#define CARD_PAGE_INFO2 7
#define CARD_PAGE_START 8
#define CARD_PAGE_PASS 5
#define CARD_PAGE_DATE 6
#define CARD_PAGE_TIME 7
#define CARD_PAGE_STATION_NUM 6
#define CARD_PAGE_BACKUP_START 6
#define PAGE_CFG0_OFFSET 2
#define PAGE_CFG1_OFFSET 3
#define PAGE_PWD_OFFSET 4
#define PAGE_PACK_OFFSET 5
enum class CardType : byte {
UNKNOWN = 0,
ISO_14443_4 = 1,
ISO_18092 = 2,
MIFARE_MINI = 3,
MIFARE_1K = 4,
MIFARE_4K = 5,
MIFARE_UL = 6,
MIFARE_PLUS = 7,
TNP3XXX = 8,
NTAG213 = 9,
NTAG215 = 10,
NTAG216 = 11
};
typedef struct {
byte pass[4];
byte pack[2];
} NtagAuthPassword;
class Rfid {
public:
void init(uint8_t ssPin, uint8_t rstPin, uint8_t newAntennaGain = DEFAULT_ANTENNA_GAIN);
void clearLastCardUid();
void setAntennaGain(uint8_t newAntennaGain);
void setAuthPassword(uint8_t *password);
/**
* Begins to work with RFID module
* Turn on RC522, detect a card and return the card type if a new one has presented else return 0 if the same card has presented or 0xFF if no any card
*/
void begin(uint8_t newAntennaGain = 0);
/**
* Stops to work with RFID module
*/
void end();
/**
* Returns true if any card has been detected by RFID module
*/
bool isCardDetected();
bool isNewCardDetected();
bool cardWrite(uint8_t startPageAdr, const byte *data, uint16_t size);
bool cardErase(uint8_t beginPageAddr, uint8_t endPageAddr);
bool cardPageErase(uint8_t pageAddr);
bool cardErase4Pages(uint8_t pageAddr);
/**
* Reads data from a card page. Buffer size should be 4 bytes!
*/
bool cardPageRead(uint8_t pageAdr, byte *data, uint8_t size = 4, bool ignoreAuthError = true);
/**
* Writes data to a card page. Buffer size should be 4 bytes!
*/
bool cardPageWrite(uint8_t pageAdr, const byte *data, uint8_t size = 4, bool ignoreAuthError = true);
bool cardPageWrite(uint8_t pageAdr, uint32_t value);
/**
* Returns max page address of the presented card
*/
uint8_t getCardMaxPage();
/**
* Returns type of the card
*/
CardType getCardType();
bool cardEnableDisableAuthentication(bool writeProtection, bool readProtection = false);
private:
// data buffer size should be greater 18 bytes
bool mifareCardPageRead(uint8_t pageAdr, byte *data, byte *size);
// data buffer size should be greater 16 bytes
bool mifareCardPageWrite(uint8_t pageAdr, byte *data, byte size);
// data buffer size should be greater 18 bytes
bool ntagCard4PagesRead(uint8_t pageAdr, byte *data, byte *size, bool ignoreAuthError = true);
bool ntagTryAuth(bool ignoreAuthError);
bool ntagAuth(NtagAuthPassword *password);
bool ntagSetPassword(NtagAuthPassword *password, bool readAndWrite, uint8_t negAuthAttemptsLim, uint8_t startPage);
bool ntagDisableAuthentication();
// data buffer size should be greater 4 bytes
bool ntagCardPageWrite(uint8_t pageAdr, byte *data, byte size, bool ignoreAuthError = true);
MFRC522 mfrc522;
NtagAuthPassword authPwd;
MFRC522::Uid lastCardUid;
uint8_t rfidSsPin = 0;
uint8_t rfidRstPin = 0;
uint8_t antennaGain = 0;
CardType cardType = CardType::UNKNOWN;
bool authenticated = false;
};
#endif // SPORTIDUINO_RFID_H
@@ -0,0 +1,259 @@
#include <EEPROM.h>
#include <Adafruit_SleepyDog.h>
#include <string.h>
#include "sportiduino.h"
#define SERIAL_DATA_MAX_SIZE 28
#define SERIAL_TIMEOUT 10
void majEepromWrite(uint16_t adr, uint8_t val) {
uint8_t oldVal = majEepromRead(adr);
if(val != oldVal) {
for(uint16_t i = 0; i < 3; i++) {
EEPROM.write(adr + i, val);
}
}
}
uint8_t majEepromRead(uint16_t adr) {
uint8_t val1 = EEPROM.read(adr);
uint8_t val2 = EEPROM.read(adr + 1);
uint8_t val3 = EEPROM.read(adr + 2);
if(val1 == val2 || val1 == val3) {
return val1;
} else if(val2 == val3) {
return val2;
}
return 0;
}
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause) {
if (pause == 0) {
pause = (ms > 200) ? 200 : ms;
}
for(uint8_t i = 0; i < n; i++) {
Watchdog.reset();
digitalWrite(ledPin, HIGH);
#if !defined(SILENT_BEEP)
if(freq > 0) {
tone(buzPin, freq, ms);
} else {
digitalWrite(buzPin, HIGH);
}
#endif
delay(ms);
Watchdog.reset();
digitalWrite(ledPin, LOW);
digitalWrite(buzPin, LOW);
if(i < n - 1) {
delay(pause);
Watchdog.reset();
}
}
}
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum) {
DEBUG_PRINTLN(F("findNewPage"));
uint8_t startPage = CARD_PAGE_START;
uint8_t endPage = rfid->getCardMaxPage() + 1; // page after last page
uint8_t page = startPage;
byte pageData[4] = {0,0,0,0};
byte num = 0;
*newPage = 0;
*lastNum = 0;
while(startPage < endPage) {
page = (startPage + endPage)/2;
DEBUG_PRINT(F("page: "));
DEBUG_PRINTLN(page);
if(!rfid->cardPageRead(page, pageData)) {
DEBUG_PRINTLN(F("page read failed"));
return false;
}
num = pageData[0];
if(num == 0) {
endPage = page;
} else {
startPage = (startPage != page)? page : page + 1;
}
}
if(num > 0) {
++page;
}
DEBUG_PRINT(F("new page: "));
DEBUG_PRINT(page);
DEBUG_PRINT(F(", num: "));
DEBUG_PRINTLN(num);
*newPage = page;
*lastNum = num;
return true;
}
bool pageIsEmpty(const byte *pageData) {
return (pageData[0] == 0 && pageData[1] == 0 && pageData[2] == 0 && pageData[3] == 0);
}
bool uint32ToByteArray(uint32_t value, byte *byteArray) {
for(uint8_t i = 0; i < 4; ++i) {
byteArray[3 - i] = value & 0xff;
value >>= 8;
}
return true;
}
uint32_t byteArrayToUint32(const byte *byteArray) {
uint32_t value = 0;
for(uint8_t i = 0; i < 4; ++i) {
value <<= 8;
value |= byteArray[i];
}
return value;
}
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress) {
uint16_t eepromAdr = eepromConfigAddress;
for(uint8_t i = 0; i < configSize; ++i) {
*((uint8_t*)config + i) = majEepromRead(eepromAdr);
eepromAdr += 3;
}
return true;
}
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress) {
uint16_t eepromAdr = eepromConfigAddress;
for(uint8_t i = 0; i < configSize; ++i) {
majEepromWrite(eepromAdr, *((uint8_t*)newConfig + i));
eepromAdr += 3;
}
return true;
}
void SerialProtocol::init(uint8_t _startByte, uint32_t _baudrate) {
startByte = _startByte;
baudrate = _baudrate;
Serial.setTimeout(SERIAL_TIMEOUT);
begin();
}
void SerialProtocol::begin() {
Serial.begin(baudrate);
}
void SerialProtocol::end() {
Serial.end();
}
void SerialProtocol::start(uint8_t code) {
serialDataPos = 3;
serialPacketCount = 0;
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
serialBuffer[0] = startByte;
serialBuffer[1] = code;
}
void SerialProtocol::send() {
uint8_t dataSize = serialDataPos - 3; // minus start, resp code, datalen
if(dataSize > SERIAL_DATA_MAX_SIZE) {
dataSize = serialPacketCount + 0x1E;
serialDataPos = SERIAL_PACKET_SIZE - 1;
serialPacketCount++;
}
serialBuffer[2] = dataSize;
serialBuffer[serialDataPos] = checkSum(serialBuffer, dataSize);
for(uint8_t i = 0; i <= serialDataPos; i++) {
Serial.write(serialBuffer[i]);
}
serialDataPos = 3;
}
void SerialProtocol::add(uint8_t dataByte) {
if(serialDataPos >= SERIAL_PACKET_SIZE - 1) {
serialDataPos++; // to indicate that we going to send packet count
send();
}
serialBuffer[serialDataPos] = dataByte;
serialDataPos++;
}
void SerialProtocol::addUint32(uint32_t data) {
uint8_t b[4];
uint32ToByteArray(data, b);
add(b, 4);
}
void SerialProtocol::add(const uint8_t *data, uint8_t size) {
for(uint8_t i = 0; i < size; ++i) {
add(data[i]);
}
}
uint8_t SerialProtocol::checkSum(uint8_t *buffer, uint8_t dataSize) {
// if at dataSize position we have packet count
if(dataSize > SERIAL_DATA_MAX_SIZE) {
dataSize = SERIAL_DATA_MAX_SIZE;
}
uint8_t len = dataSize + 2; // + cmd/resp byte + length byte
uint8_t sum = 0;
for (uint8_t i = 1; i <= len; ++i) {
sum += buffer[i];
}
return sum;
}
uint8_t *SerialProtocol::read(bool *error, uint8_t *code, uint8_t *dataSize) {
*error = false;
memset(serialBuffer, 0, SERIAL_PACKET_SIZE);
if(Serial.available() > 0) {
uint8_t b = Serial.peek();
if(b == startByte) {
Serial.readBytes(serialBuffer, SERIAL_PACKET_SIZE);
*dataSize = serialBuffer[2];
// if at dataSize position we have packet count
if(*dataSize > SERIAL_DATA_MAX_SIZE) {
*dataSize = SERIAL_DATA_MAX_SIZE;
}
if(serialBuffer[*dataSize + 3] != checkSum(serialBuffer, *dataSize)) {
*error = true;
return nullptr;
}
*code = serialBuffer[1];
return &serialBuffer[3];
}
}
return nullptr;
}
void SerialProtocol::dropByte() {
if(Serial.available() > 0) {
// Drop byte
Serial.read();
}
}
@@ -0,0 +1,83 @@
#ifndef SPORTIDUINO_H
#define SPORTIDUINO_H
#include <Arduino.h>
#include "debug.h"
#include "rfid.h"
enum StationNum {
START_STATION_NUM = 240,
FINISH_STATION_NUM = 245,
CHECK_STATION_NUM = 248,
CLEAR_STATION_NUM = 249
};
enum MasterCard {
MASTER_CARD_AUTH_PASSWORD = 248,
MASTER_CARD_STATE = 249,
MASTER_CARD_SET_TIME = 250,
MASTER_CARD_SET_NUMBER = 251,
MASTER_CARD_SLEEP = 252,
MASTER_CARD_READ_BACKUP = 253,
MASTER_CARD_CONFIG = 254,
MASTER_CARD_PASSWORD = 255
};
#define MASTER_CARD_SIGN 0xff
#define FAST_PUNCH_SIGN 0xaa // page6[3]
#define SERIAL_PACKET_SIZE 32
#define MAX_FW_MINOR_VERS 239
/**
* Writes data with a majority backup in three cells of EEPROM
*/
void majEepromWrite (uint16_t adr, uint8_t val);
/**
* Reads data with a majority backup from EEPROM
*/
uint8_t majEepromRead(uint16_t adr);
/**
* Turn on led and buzzer for given ms n times
* @param freq the frequency of your buzzer if you have solded the buzzer without a generator else 0
*/
void beep_w(const uint8_t ledPin, const uint8_t buzPin, uint16_t freq, uint16_t ms, uint8_t n, uint16_t pause = 0);
bool findNewPage(Rfid *rfid, uint8_t *newPage, uint8_t *lastNum);
bool pageIsEmpty(const byte *pageData);
bool uint32ToByteArray(uint32_t value, byte *byteArray);
uint32_t byteArrayToUint32(const byte *byteArray);
bool pageIsEmpty(const byte *pageData);
bool readConfig(uint8_t *config, uint8_t configSize, uint16_t eepromConfigAddress);
bool writeConfig(uint8_t *newConfig, uint8_t configSize, uint16_t eepromConfigAddress);
class SerialProtocol {
public:
void init(uint8_t _startByte, uint32_t baudrate = 9600);
void begin();
void end();
void start(uint8_t code);
void add(uint8_t dataByte);
void addUint32(uint32_t data);
void add(const uint8_t *data, uint8_t size);
void send();
uint8_t *read(bool *error, uint8_t *code, uint8_t *dataSize);
void dropByte();
private:
uint8_t checkSum(uint8_t *buffer, uint8_t dataSize);
uint8_t startByte = 0;
uint8_t serialBuffer[SERIAL_PACKET_SIZE];
uint8_t serialDataPos = 3;
uint8_t serialPacketCount = 0;
uint32_t baudrate = 0;
};
#endif