Add basic card/reader type identification
This commit is contained in:
parent
15215f02d0
commit
dfcfd3b5cb
|
@ -8,6 +8,7 @@ class Reader {
|
|||
public:
|
||||
virtual bool canHaveUnstableIdentifier() = 0;
|
||||
virtual bool isNewCardPresent() = 0;
|
||||
virtual String getReaderName() = 0;
|
||||
virtual String getCardUid() = 0;
|
||||
virtual void begin() = 0;
|
||||
virtual void reset() = 0;
|
||||
|
@ -22,6 +23,7 @@ public:
|
|||
explicit MFRC522Reader(byte chipSelectPin, byte resetPowerDownPin);
|
||||
bool canHaveUnstableIdentifier() override;
|
||||
bool isNewCardPresent() override;
|
||||
String getReaderName() override;
|
||||
String getCardUid() override;
|
||||
void begin() override;
|
||||
void reset() override;
|
||||
|
@ -37,6 +39,7 @@ public:
|
|||
explicit RDM6300Reader(int pin);
|
||||
bool canHaveUnstableIdentifier() override;
|
||||
bool isNewCardPresent() override;
|
||||
String getReaderName() override;
|
||||
String getCardUid() override;
|
||||
void begin() override;
|
||||
void reset() override;
|
||||
|
@ -57,6 +60,7 @@ public:
|
|||
explicit PN532Reader(uint8_t ss);
|
||||
bool canHaveUnstableIdentifier() override;
|
||||
bool isNewCardPresent() override;
|
||||
String getReaderName() override;
|
||||
String getCardUid() override;
|
||||
void cycleMode();
|
||||
void beginKeepMode();
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
unsigned long cooldownSecondsRemaining(unsigned long timeout, unsigned long timer);
|
||||
String byteArrayAsHexString(byte* buffer, byte bufferSize);
|
||||
String cardLink(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId);
|
||||
String cardBalance(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId);
|
||||
String cardTransaction(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& amount);
|
||||
String cardLink(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& reader);
|
||||
String cardBalance(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& reader);
|
||||
String cardTransaction(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& amount, const String& reader);
|
||||
String splitString(const String& data, char separator, int index);
|
||||
String cardIdDisplay(const String& id);
|
||||
|
||||
|
|
|
@ -315,7 +315,7 @@ void loop() {
|
|||
tone(PIN_BUZZER, NOTE_NONE, 150);
|
||||
}
|
||||
|
||||
lastStatusText = cardTransaction(wifi, http, apiUrl, scannedCardId, String(GetTransactionAmount()));
|
||||
lastStatusText = cardTransaction(wifi, http, apiUrl, scannedCardId, String(GetTransactionAmount()), scannedCardReader->getReaderName());
|
||||
if (lastStatusText.startsWith("S:")) {
|
||||
tone(PIN_BUZZER, NOTE_C7, 650);
|
||||
state = STATE_RESULT_SUCCESS;
|
||||
|
@ -385,7 +385,7 @@ void loop() {
|
|||
tone(PIN_BUZZER, NOTE_NONE, 150);
|
||||
}
|
||||
|
||||
lastStatusText = cardLink(wifi, http, apiUrl, scannedCardId);
|
||||
lastStatusText = cardLink(wifi, http, apiUrl, scannedCardId, scannedCardReader->getReaderName());
|
||||
if (lastStatusText.startsWith("S:")) {
|
||||
tone(PIN_BUZZER, NOTE_C6, 100);
|
||||
tone(PIN_BUZZER, NOTE_NONE, 10);
|
||||
|
@ -404,6 +404,7 @@ void loop() {
|
|||
for (Reader* reader : readers) {
|
||||
if (reader->isNewCardPresent()) {
|
||||
scannedCardId = reader->getCardUid();
|
||||
scannedCardReader = reader;
|
||||
lastStatusText = cardIdDisplay(scannedCardId);
|
||||
state = STATE_BALANCE_VERIFY;
|
||||
return;
|
||||
|
@ -427,7 +428,7 @@ void loop() {
|
|||
tone(PIN_BUZZER, NOTE_NONE, 150);
|
||||
}
|
||||
|
||||
lastStatusText = cardBalance(wifi, http, apiUrl, scannedCardId);
|
||||
lastStatusText = cardBalance(wifi, http, apiUrl, scannedCardId, scannedCardReader->getReaderName());
|
||||
if (lastStatusText.startsWith("S:")) {
|
||||
lastStatusText = lastStatusText + ":" + cardIdDisplay(scannedCardId);
|
||||
state = STATE_RESULT_DISPLAY;
|
||||
|
|
|
@ -34,3 +34,7 @@ void MFRC522Reader::init() {
|
|||
mfrc522->PCD_Init();
|
||||
mfrc522->PCD_DumpVersionToSerial();
|
||||
}
|
||||
|
||||
String MFRC522Reader::getReaderName() {
|
||||
return "mfrc522";
|
||||
}
|
||||
|
|
|
@ -98,3 +98,7 @@ void PN532Reader::init() {
|
|||
Serial.print("Firmware ver. "); Serial.print((version>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((version>>8) & 0xFF, DEC);
|
||||
}
|
||||
|
||||
String PN532Reader::getReaderName() {
|
||||
return mode == PN532_MIFARE_ISO14443A ? "pn532-iso14443a" : "pn532-felica";
|
||||
}
|
||||
|
|
|
@ -40,3 +40,7 @@ void RDM6300Reader::init() {
|
|||
rdm6300->begin(pin);
|
||||
rdm6300->set_tag_timeout(65);
|
||||
}
|
||||
|
||||
String RDM6300Reader::getReaderName() {
|
||||
return "rdm6300";
|
||||
}
|
||||
|
|
|
@ -45,8 +45,8 @@ String splitString(const String& data, char separator, int index) {
|
|||
}
|
||||
|
||||
|
||||
String cardLink(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId) {
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/link";
|
||||
String cardLink(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& reader) {
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/link" + "?reader=" + reader;
|
||||
http->begin(*wifi, finalRequestUrl.c_str());
|
||||
http->addHeader("Content-Type", "application/json");
|
||||
int httpResponseCode = http->PUT("");
|
||||
|
@ -84,8 +84,8 @@ String cardLink(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const
|
|||
return String("E:Internal Error ") + httpResponseCode;
|
||||
}
|
||||
|
||||
String cardBalance(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId) {
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/balance";
|
||||
String cardBalance(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& reader) {
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/balance" + "?reader=" + reader;
|
||||
http->begin(*wifi, finalRequestUrl.c_str());
|
||||
http->addHeader("Content-Type", "application/json");
|
||||
int httpResponseCode = http->GET();
|
||||
|
@ -121,9 +121,9 @@ String cardBalance(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, con
|
|||
return String("E:Internal Error ") + httpResponseCode;
|
||||
}
|
||||
|
||||
String cardTransaction(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& amount) {
|
||||
String cardTransaction(WiFiClient* wifi, HTTPClient* http, const String& apiUrl, const String& cardId, const String& amount, const String& reader) {
|
||||
String idempotencyKey = getIdempotencyKey();
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/transaction/" + idempotencyKey + "?amount=" + amount;
|
||||
String finalRequestUrl = apiUrl + "/api/card/" + cardId + "/transaction/" + idempotencyKey + "?amount=" + amount + "&reader=" + reader;
|
||||
http->begin(*wifi, finalRequestUrl.c_str());
|
||||
http->addHeader("Content-Type", "application/json");
|
||||
int httpResponseCode = http->PUT("");
|
||||
|
|
|
@ -13,6 +13,7 @@ public class CardController : Controller {
|
|||
/// Links the given card to the user currently in link mode.
|
||||
/// </summary>
|
||||
/// <param name="card">The ID of the card</param>
|
||||
/// <param name="reader">Type of reader that scanned the card</param>
|
||||
/// <response code="200">Returns 200 if the link succeeded</response>
|
||||
/// <response code="304">Returns 304 if the card was already linked</response>
|
||||
/// <response code="404">Returns 404 if no link process is active</response>
|
||||
|
@ -24,7 +25,7 @@ public class CardController : Controller {
|
|||
[SwaggerResponseExample(StatusCodes.Status200OK, typeof(UserUpdatedExample))]
|
||||
[SwaggerResponseExample(StatusCodes.Status404NotFound, typeof(ErrorNoActiveLinkProcessExample))]
|
||||
[Route("/api/card/{card}/link")]
|
||||
public async Task<IActionResult> Link(string card) {
|
||||
public async Task<IActionResult> Link(string card, [FromQuery] string? reader) {
|
||||
var db = new DatabaseContext();
|
||||
if (db.Cards.Any(p => p.Id == card)) {
|
||||
return StatusCode(StatusCodes.Status304NotModified);
|
||||
|
@ -48,7 +49,7 @@ public class CardController : Controller {
|
|||
var user = db.Users.First(p => p.Id == int.Parse(linkFlag.Value));
|
||||
linkFlag.Value = "";
|
||||
|
||||
var type = card.Length == 10 && long.TryParse(card, out _) ? Card.CardType.Rfid125KhzGeneric : Card.CardType.Unknown;
|
||||
var type = GetCardType(reader, card);
|
||||
|
||||
db.Add(new Card { Id = card, User = user, Type = type });
|
||||
await db.SaveChangesAsync();
|
||||
|
@ -61,6 +62,7 @@ public class CardController : Controller {
|
|||
/// <param name="card">The ID of the card</param>
|
||||
/// <param name="ik">Random string (idempotency key) which is consistent across request retries</param>
|
||||
/// <param name="amount">Positive or negative number of cents representing the relative change in balance</param>
|
||||
/// <param name="reader">Type of reader that scanned the card</param>
|
||||
/// <response code="200">Returns 200 if the transaction succeeded</response>
|
||||
/// <response code="404">Returns 404 if the card isn't linked to any account</response>
|
||||
/// <response code="412">Returns 412 if the transaction failed because the balance would be out of range after the transaction</response>
|
||||
|
@ -73,7 +75,7 @@ public class CardController : Controller {
|
|||
[SwaggerResponseExample(404, typeof(ErrorUnknownCardExample))]
|
||||
[SwaggerResponseExample(412, typeof(ErrorBalanceOutOfRangeExample))]
|
||||
[Route("/api/card/{card}/transaction/{ik}")]
|
||||
public async Task<IActionResult> Transaction(string card, string ik, [FromQuery] int amount) {
|
||||
public async Task<IActionResult> Transaction(string card, string ik, [FromQuery] int amount, [FromQuery] string? reader) {
|
||||
var db = new DatabaseContext();
|
||||
if (db.Cards.Any(p => p.Id == card)) {
|
||||
var user = db.Cards.Include(p => p.User).First(p => p.Id == card).User;
|
||||
|
@ -88,6 +90,12 @@ public class CardController : Controller {
|
|||
user.Balance += amount;
|
||||
}
|
||||
|
||||
var dbCard = db.Cards.First(p => p.Id == card);
|
||||
var newType = GetCardType(reader, card);
|
||||
|
||||
if (dbCard.Type != newType)
|
||||
dbCard.Type = newType;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
return Ok(new UserResponse(user));
|
||||
}
|
||||
|
@ -99,6 +107,7 @@ public class CardController : Controller {
|
|||
/// Returns the balance of the the user the card is linked to.
|
||||
/// </summary>
|
||||
/// <param name="card">The ID of the card</param>
|
||||
/// <param name="reader">Type of reader that scanned the card</param>
|
||||
/// <response code="200">Returns 200 if the request succeeded</response>
|
||||
/// <response code="404">Returns 404 if the card isn't linked to any account</response>
|
||||
[HttpGet]
|
||||
|
@ -108,10 +117,18 @@ public class CardController : Controller {
|
|||
[SwaggerResponseExample(200, typeof(UserUpdatedExample))]
|
||||
[SwaggerResponseExample(404, typeof(ErrorUnknownCardExample))]
|
||||
[Route("/api/card/{card}/balance")]
|
||||
public IActionResult Balance(string card) {
|
||||
public IActionResult Balance(string card, [FromQuery] string? reader) {
|
||||
var db = new DatabaseContext();
|
||||
if (db.Cards.Any(p => p.Id == card)) {
|
||||
var user = db.Cards.Include(p => p.User).First(p => p.Id == card).User;
|
||||
|
||||
var dbCard = db.Cards.First(p => p.Id == card);
|
||||
var newType = GetCardType(reader, card);
|
||||
|
||||
if (dbCard.Type != newType) {
|
||||
dbCard.Type = newType;
|
||||
db.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return Ok(new UserResponse(user));
|
||||
}
|
||||
|
@ -134,4 +151,15 @@ public class CardController : Controller {
|
|||
private class ErrorNoActiveLinkProcessExample : IExamplesProvider<ErrorResponse> {
|
||||
public ErrorResponse GetExamples() => new("No active link process");
|
||||
}
|
||||
|
||||
private Card.CardType GetCardType(string? reader, string cardNumber) {
|
||||
//TODO match more specific type based on card number format
|
||||
|
||||
return reader switch {
|
||||
"rdm6300" => Card.CardType.Rfid125KhzGeneric,
|
||||
"pn532-iso14443a" => Card.CardType.NfcGeneric,
|
||||
"pn532-felica" => Card.CardType.FeliCaGeneric,
|
||||
_ => Card.CardType.Unknown
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue