proxmark3/armsrc/util.c
iceman1001 f5bff0d4e5 style
2019-09-13 16:27:25 +02:00

333 lines
8.8 KiB
C

//-----------------------------------------------------------------------------
// Jonathan Westhues, Sept 2005
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Utility functions used in many places, not specific to any piece of code.
//-----------------------------------------------------------------------------
#include "util.h"
#include "proxmark3_arm.h"
#include "ticks.h"
#include "commonutil.h"
#include "dbprint.h"
#include "string.h"
#include "usb_cdc.h"
#include "usart.h"
size_t nbytes(size_t nbits) {
return (nbits >> 3) + ((nbits % 8) > 0);
}
//convert hex digit to integer
uint8_t hex2int(char hexchar) {
switch (hexchar) {
case '0':
return 0;
break;
case '1':
return 1;
break;
case '2':
return 2;
break;
case '3':
return 3;
break;
case '4':
return 4;
break;
case '5':
return 5;
break;
case '6':
return 6;
break;
case '7':
return 7;
break;
case '8':
return 8;
break;
case '9':
return 9;
break;
case 'a':
case 'A':
return 10;
break;
case 'b':
case 'B':
return 11;
break;
case 'c':
case 'C':
return 12;
break;
case 'd':
case 'D':
return 13;
break;
case 'e':
case 'E':
return 14;
break;
case 'f':
case 'F':
return 15;
break;
default:
return 0;
}
}
void LEDsoff() {
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
}
//ICEMAN: LED went from 1,2,3,4 -> 1,2,4,8
void LED(int led, int ms) {
if (led & LED_A) // Proxmark3 historical mapping: LED_ORANGE
LED_A_ON();
if (led & LED_B) // Proxmark3 historical mapping: LED_GREEN
LED_B_ON();
if (led & LED_C) // Proxmark3 historical mapping: LED_RED
LED_C_ON();
if (led & LED_D) // Proxmark3 historical mapping: LED_RED2
LED_D_ON();
if (!ms)
return;
SpinDelay(ms);
if (led & LED_A)
LED_A_OFF();
if (led & LED_B)
LED_B_OFF();
if (led & LED_C)
LED_C_OFF();
if (led & LED_D)
LED_D_OFF();
}
void SpinOff(uint32_t pause) {
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
SpinDelay(pause);
}
// Blinks..
// A = 1, B = 2, C = 4, D = 8
void SpinErr(uint8_t led, uint32_t speed, uint8_t times) {
SpinOff(speed);
NTIME(times) {
if (led & LED_A) // Proxmark3 historical mapping: LED_ORANGE
LED_A_INV();
if (led & LED_B) // Proxmark3 historical mapping: LED_GREEN
LED_B_INV();
if (led & LED_C) // Proxmark3 historical mapping: LED_RED
LED_C_INV();
if (led & LED_D) // Proxmark3 historical mapping: LED_RED2
LED_D_INV();
SpinDelay(speed);
}
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
}
void SpinDown(uint32_t speed) {
SpinOff(speed);
LED_D_ON();
SpinDelay(speed);
LED_D_OFF();
LED_C_ON();
SpinDelay(speed);
LED_C_OFF();
LED_B_ON();
SpinDelay(speed);
LED_B_OFF();
LED_A_ON();
SpinDelay(speed);
LED_A_OFF();
}
void SpinUp(uint32_t speed) {
SpinOff(speed);
LED_A_ON();
SpinDelay(speed);
LED_A_OFF();
LED_B_ON();
SpinDelay(speed);
LED_B_OFF();
LED_C_ON();
SpinDelay(speed);
LED_C_OFF();
LED_D_ON();
SpinDelay(speed);
LED_D_OFF();
}
// Determine if a button is double clicked, single clicked,
// not clicked, or held down (for ms || 1sec)
// In general, don't use this function unless you expect a
// double click, otherwise it will waste 500ms -- use BUTTON_HELD instead
int BUTTON_CLICKED(int ms) {
// Up to 500ms in between clicks to mean a double click
// timer counts in 21.3us increments (1024/48MHz)
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
if (ms > 1390) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf(_RED_("Error, BUTTON_CLICKED called with %i > 1390"), ms);
ms = 1390;
}
int ticks = ((MCK / 1000) * (ms ? ms : 1000)) >> 10;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
int letoff = 0;
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// We haven't let off the button yet
if (!letoff) {
// We just let it off!
if (!BUTTON_PRESS()) {
letoff = 1;
// reset our timer for 500ms
start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
ticks = ((MCK / 1000) * (500)) >> 10;
}
// Still haven't let it off
else
// Have we held down a full second?
if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
}
// We already let off, did we click again?
else
// Sweet, double click!
if (BUTTON_PRESS())
return BUTTON_DOUBLE_CLICK;
// Have we ran out of time to double click?
else if (now == (uint16_t)(start + ticks))
// At least we did a single click
return BUTTON_SINGLE_CLICK;
WDT_HIT();
}
// We should never get here
return BUTTON_ERROR;
}
// Determine if a button is held down
int BUTTON_HELD(int ms) {
// timer counts in 21.3us increments (1024/48MHz)
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
if (ms > 1390) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf(_RED_("Error, BUTTON_HELD called with %i > 1390"), ms);
ms = 1390;
}
// If button is held for one second
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// As soon as our button let go, we didn't hold long enough
if (!BUTTON_PRESS())
return BUTTON_SINGLE_CLICK;
// Have we waited the full second?
else if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
WDT_HIT();
}
// We should never get here
return BUTTON_ERROR;
}
/* Similar to FpgaGatherVersion this formats stored version information
* into a string representation. It takes a pointer to the struct version_information,
* verifies the magic properties, then stores a formatted string, prefixed by
* prefix in dst.
*/
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information) {
struct version_information *v = (struct version_information *)version_information;
dst[0] = 0;
strncat(dst, prefix, len - 1);
if (v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1);
return;
}
if (v->versionversion != 1) {
strncat(dst, "Version information not understood\n", len - strlen(dst) - 1);
return;
}
if (!v->present) {
strncat(dst, "Version information not available\n", len - strlen(dst) - 1);
return;
}
strncat(dst, v->gitversion, len - strlen(dst) - 1);
if (v->clean == 0) {
strncat(dst, "-unclean", len - strlen(dst) - 1);
} else if (v->clean == 2) {
strncat(dst, "-suspect", len - strlen(dst) - 1);
}
strncat(dst, " ", len - strlen(dst) - 1);
strncat(dst, v->buildtime, len - strlen(dst) - 1);
strncat(dst, "\n", len - strlen(dst) - 1);
}
bool data_available(void) {
#ifdef WITH_FPC_USART_HOST
return usb_poll_validate_length() || (usart_rxdata_available() > 0);
#else
return usb_poll_validate_length();
#endif
}