Initial checkin.
This commit is contained in:
commit
d853bc95d9
31 changed files with 5815 additions and 0 deletions
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
*.hex
|
||||
*.bin
|
||||
*.eep
|
||||
*.o
|
||||
*.elf
|
||||
*.map
|
||||
*.lss
|
||||
*.lst
|
||||
*.d
|
||||
*.sym
|
||||
.idea
|
||||
|
||||
LUFA/
|
19
LICENSE
Normal file
19
LICENSE
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2014 flabbergast at sdfeu dott org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
81
README.md
Normal file
81
README.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
# sha204_playground
|
||||
|
||||
Firmware for ATMEL chips to communicate with ATSHA204 chip interactively
|
||||
over Serial. Sources are supplied in two forms:
|
||||
|
||||
- As AVR-GCC project utilizing the [LUFA] library (for USB capable
|
||||
ATMEL chips, tested on atmega32U4 and atxmega128a3u).
|
||||
- As an [Arduino] sketch.
|
||||
|
||||
Along with this, a python script `talk_to_sha204.py` is provided to
|
||||
access some of the functionality of the ATSHA204 chip, talking to
|
||||
it via the firmware above (in a binary mode), a-la [hashlet].
|
||||
|
||||
## Usage / Installation
|
||||
|
||||
Please see the READMEs in the individual subdirectories for some info on
|
||||
how to use them.
|
||||
|
||||
## Pictures
|
||||
|
||||
The original impetus to write this stuff for me was that I had a couple
|
||||
of ATSHA204 breakout boards from [Sparkfun] and I wanted to play with
|
||||
them outside Arduino, using just avr-gcc and [LUFA], on some USB sticks
|
||||
with ATMEL chips. Here are pics with two of them:
|
||||
|
||||

|
||||
|
||||
And matrixstorm's [AVR stick] with the same Sparkfun's ATSHA breakout:
|
||||
|
||||

|
||||
|
||||
|
||||
## Idle thoughts / ramblings
|
||||
|
||||
So, what can be ATSHA204 used for? Well, it performs hashing (SHA256)
|
||||
and it can securely store "keys" (32 bytes long blocks of data).
|
||||
|
||||
The important point (for me) is that to verify that a "signature" (hash,
|
||||
MAC) was generated on a particular ATSHA requires knowing all the
|
||||
"secrets" that were used to generate the signature. This works fine for
|
||||
Client/Server-like situations: "Client" ATSHA generates a signature for,
|
||||
say, a file, (e.g. on a local computer), which is then sent to "Server"
|
||||
for verification. However the "Server" has to know the "secret keys" on
|
||||
ATSHA that were used in the signature computation; so either the
|
||||
"Server" has a copy of the keys stored in ATSHA, or there's another
|
||||
ATSHA on the "Server" with the keys.
|
||||
|
||||
This kind of thing can be used for instance to roll one's own
|
||||
authentication service a-la [YubiKey].
|
||||
|
||||
What I wanted to use it for is to securely store encryption keys
|
||||
locally, for a "two-factor key storage". This is also possible to do:
|
||||
user enters a password, this is passed to ATSHA which generates a hash
|
||||
of the user's password, together with one of its "secret keys". This
|
||||
hash is then used as an encryption key. So to obtain the
|
||||
encryption key, one has to know the password and have the ATSHA along.
|
||||
|
||||
## Notes
|
||||
|
||||
Please see the READMEs in the individual subdirectories for more info
|
||||
about the various parts of the project, as well as credits.
|
||||
|
||||
## TODO / Roadmap
|
||||
|
||||
- Make also binary-mode-only versions of the firmware (for smaller than
|
||||
32kB chips).
|
||||
|
||||
## License
|
||||
|
||||
My code is (c) flabbergast. MIT license (see LICENSE file). Portions
|
||||
of the code come from LUFA demos, this is licensed by LUFA's license.
|
||||
The original code from SHA204 library is licensed by Apache V2.0 license.
|
||||
|
||||
|
||||
[AVRstick]: http://matrixstorm.com/avr/avrstick/
|
||||
[LUFA]: http://www.fourwalledcubicle.com/LUFA.php
|
||||
[hashlet]: https://github.com/cryptotronix/hashlet
|
||||
[YubiKey]: https://www.yubico.com/products/yubikey-hardware/yubikey-2/
|
||||
[Arduino]: http://www.arduino.cc/
|
||||
[Sparkfun]: https://www.sparkfun.com/products/11551
|
||||
[AVR stick]: http://matrixstorm.com/avr/avrstick/
|
47
arduino/README.md
Normal file
47
arduino/README.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# sha204_playground firmware: Arduino version
|
||||
|
||||
## Installation / usage
|
||||
|
||||
Copy the `avr/SHA204` library to your Arduino IDE's `libraries` folder,
|
||||
and copy the sketch `sha204_playground_arduino` to your sketchbook.
|
||||
|
||||
Make the modifications to the library file
|
||||
`SHA204/SHA204SWI_hardware_config.h` to match your hardware setup (i.e.
|
||||
to which pin is your ATSHA204 connected to).
|
||||
|
||||
Compile and upload the sketch to your Arduino using IDE. Open the IDE's
|
||||
Serial Monitor to talk to the Arduino/ATSHA204.
|
||||
|
||||
Note that I've tested on Arduino IDE version 1.0.5.
|
||||
|
||||
## Problems
|
||||
|
||||
Arduino sets the size of the Serial buffer to 64. This seems to cause
|
||||
problems when the data sent to firmware is longer than that (which it is
|
||||
for instance with the `talk_to_sha204 check_mac` command). If things
|
||||
work, but you get a weird error with this command, increase the size of
|
||||
the Serial buffer. Unfortunately, this requires editing a file in the
|
||||
Arduino directory:
|
||||
`<ARDUINO_APP_DIR>/<MAYBE_SOME_MORE_DIRS/hardware/arduino/cores/arduino/HardwareSerial.cpp`,
|
||||
change `#define SERIAL_BUFFER_SIZE 64` to `#define SERIAL_BUFFER_SIZE
|
||||
100`.
|
||||
|
||||
## Communicating with the firmware
|
||||
|
||||
Probably the first thing to try is pressing `k` (to test waking the
|
||||
ATSHA up) and pressing `s` (to print the serial number of your device).
|
||||
|
||||
Alternatively (depending on the functionality required), you can use the
|
||||
`talk_to_sha204.py` script to talk to the ATSHA via this firmware.
|
||||
|
||||
### Binary mode
|
||||
|
||||
The firmware supports a "binary mode", for use with scripts. For a
|
||||
demonstration on how this is done, have a look at the python script
|
||||
`talk_to_sha204.py`.
|
||||
|
||||
## License
|
||||
|
||||
My code is (c) flabbergast. MIT license (see LICENSE file). Portions
|
||||
of the code come from LUFA demos, this is licensed by LUFA's license.
|
||||
The original code from SHA204 library is licensed by Apache V2.0 license.
|
810
arduino/sha204_playground.ino
Normal file
810
arduino/sha204_playground.ino
Normal file
|
@ -0,0 +1,810 @@
|
|||
/*
|
||||
* sha204_playground.ino
|
||||
* (c) 2014 flabbergast
|
||||
*
|
||||
* Firmware for USB capable ATMEL chips (tested on atmega32U4 and
|
||||
* atxmega128a3u) to communicate with ATSHA204 (single-wire
|
||||
* interface) interactively, over Serial.
|
||||
*
|
||||
* The code is quite ugly ... one reason being that it's just an Arduino adaptatation
|
||||
* of the original avr-gcc/LUFA code, so some of the things are unnecessarily complicated.
|
||||
* I like to keep it this way, so that it's easier to merge any patches/changes to the
|
||||
* original code.
|
||||
*/
|
||||
|
||||
#include "SHA204SWI.h"
|
||||
#include "SHA204Definitions.h" // for constants and such
|
||||
#include "SHA204ReturnCodes.h" // want messages for return codes
|
||||
|
||||
/*************************************************************************
|
||||
* ----------------------- Global variables -----------------------------*
|
||||
*************************************************************************/
|
||||
|
||||
// when this byte is received, switch to binary mode
|
||||
#define BINARY_MODE_CHAR 0xFD
|
||||
|
||||
#define MAX_BUFFER_SIZE 100
|
||||
volatile uint8_t idle = 0;
|
||||
volatile uint8_t hexprint_separator = ' ';
|
||||
|
||||
SHA204SWI sha204;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* ----------------------- Helper functions -----------------------------*
|
||||
*************************************************************************/
|
||||
void hexprint(uint8_t *p, uint16_t length);
|
||||
void hexprint_noln(uint8_t *p, uint16_t length);
|
||||
void hexprint_byte(uint8_t b);
|
||||
void hexprint_byte_sep(uint8_t b);
|
||||
|
||||
uint8_t get_bytes_serial(uint8_t *output, uint16_t len);
|
||||
void print_help(void);
|
||||
void print_executing(void);
|
||||
void print_received_from_sha(uint8_t *rx_buffer);
|
||||
void print_execute_params(uint8_t opcode, uint8_t param1);
|
||||
void print_return_code(uint8_t code);
|
||||
|
||||
void process_config(uint8_t *config);
|
||||
void sleep_or_idle(SHA204SWI *sha204);
|
||||
uint8_t receive_serial_binary_transaction(uint8_t *buffer, uint8_t len);
|
||||
uint8_t binary_mode_transaction(uint8_t *data, uint8_t rxsize, uint8_t *rx_buffer, SHA204SWI *sha204);
|
||||
#define BINARY_TRANSACTION_OK 0
|
||||
#define BINARY_TRANSACTION_RECEIVE_ERROR 1
|
||||
#define BINARY_TRANSACTION_PARAM_ERROR 2
|
||||
#define BINARY_TRANSACTION_EXECUTE_ERROR 3
|
||||
|
||||
/* A hack so that I don't have to edit too much code from the original AVR code */
|
||||
// Declarations originally from LufaLayer.h
|
||||
uint16_t usb_serial_available(void); // number of getchars guaranteed to succeed immediately
|
||||
int16_t usb_serial_getchar(void); // negative values mean error in receiving (not connected or no input)
|
||||
void usb_serial_putchar(uint8_t ch);
|
||||
void usb_serial_write(const char* const buffer);
|
||||
void usb_serial_write_P(PGM_P data);;
|
||||
uint16_t usb_serial_readline(char *buffer, const uint16_t buffer_size, const bool obscure_input); // BLOCKING (takes care of _tasks)
|
||||
#define W(s) Serial.print(F(s))
|
||||
#define Wl(s) Serial.println(F(s))
|
||||
|
||||
/* Setup */
|
||||
void setup(void)
|
||||
{
|
||||
sha204.power_up();
|
||||
|
||||
/* Initialisation */
|
||||
Serial.begin(115200);
|
||||
|
||||
print_help();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/* Variables */
|
||||
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
|
||||
uint8_t tx_buffer[MAX_BUFFER_SIZE];
|
||||
uint8_t configuration_zone[88];
|
||||
uint8_t r;
|
||||
uint8_t param1;
|
||||
uint16_t param2;
|
||||
uint8_t data1[32];
|
||||
uint8_t data2[32];
|
||||
uint8_t data3[14];
|
||||
|
||||
// main serial processing
|
||||
if(usb_serial_available() > 0) {
|
||||
byte c = (byte)usb_serial_getchar();
|
||||
if(c==BINARY_MODE_CHAR) { // handle binary mode for one transaction
|
||||
r = receive_serial_binary_transaction(tx_buffer, MAX_BUFFER_SIZE); // blocking
|
||||
if(r == BINARY_TRANSACTION_OK)
|
||||
r = binary_mode_transaction(tx_buffer, SHA204_RSP_SIZE_MAX, rx_buffer, &sha204); // blocking
|
||||
// transmit the response
|
||||
usb_serial_putchar(r);
|
||||
if(r == BINARY_TRANSACTION_OK)
|
||||
for(r=0; r<rx_buffer[0]; r++)
|
||||
usb_serial_putchar(rx_buffer[r]);
|
||||
} else {
|
||||
if(idle)
|
||||
Wl("--- I ---");
|
||||
else
|
||||
Wl("--- S ---");
|
||||
switch(c) { // yes, code like this sucks
|
||||
case 's': // serial number
|
||||
Wl("Request serial number.");
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.serialNumber(rx_buffer);
|
||||
print_executing();
|
||||
print_return_code(r);
|
||||
Wl("Should get: 01 23 xx xx xx xx xx xx EE");
|
||||
W("Received SN: ");
|
||||
hexprint(rx_buffer, 9);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
break;
|
||||
case 'o': // config zone
|
||||
Wl("Request and display config zone contents.");
|
||||
print_executing();
|
||||
memset(configuration_zone,0,32);
|
||||
if(!(r=sha204.wakeup(rx_buffer))) { // read first 2 32-byte blocks manually
|
||||
if(!(r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG|READ_ZONE_MODE_32_BYTES,0))) {
|
||||
memcpy(configuration_zone,rx_buffer+1,32);
|
||||
if(!(r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG|READ_ZONE_MODE_32_BYTES,32))) {
|
||||
memcpy(configuration_zone+32, rx_buffer+1, 32);
|
||||
uint8_t addr = 64; // have to read the rest of the zone in 4-byte blocks
|
||||
while(addr < 88) {
|
||||
if((r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG,addr)))
|
||||
break;
|
||||
memcpy(configuration_zone+addr, rx_buffer+1, 4);
|
||||
addr+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
if(!r)
|
||||
process_config(configuration_zone);
|
||||
break;
|
||||
case 'c': // check_mac
|
||||
Wl("Calculate and compare MAC (CheckMAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter client challenge (32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
Wl("Enter client response (32 bytes; default 0):");
|
||||
memset((void *)data2, 0, 32);
|
||||
get_bytes_serial(data2, 32);
|
||||
Wl("Enter other data (13 bytes; default 0):");
|
||||
memset((void *)data3, 0, 13);
|
||||
get_bytes_serial(data3, 13);
|
||||
print_execute_params(SHA204_CHECKMAC,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
W("data2 ");
|
||||
hexprint(data2, 32);
|
||||
W("data3 ");
|
||||
hexprint(data3, 13);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.check_mac(tx_buffer, rx_buffer, param1, param2, data1, data2, data3);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'd': // derive_key
|
||||
Wl("Combine current key with nonce and store in a key slot (DeriveKey command).");
|
||||
Wl("Enter random (1 byte: 00 or 04; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Target Slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter MAC for validation (0 or 32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_DERIVE_KEY,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.derive_key(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'v': // dev_rev
|
||||
Wl("Request device revision.");
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.dev_rev(tx_buffer, rx_buffer);
|
||||
print_executing();
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
break;
|
||||
case 'g': // gen_dig
|
||||
Wl("Compute SHA-256 from TempKey+stored value, store result in TempKey (GenDig command).");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Key ID / OTP slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter other data (4 bytes when CheckKey, otherwise ignored; default 0):");
|
||||
memset((void *)data1, 0, 4);
|
||||
get_bytes_serial(data1, 4);
|
||||
print_execute_params(SHA204_GENDIG,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 4);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.gen_dig(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'h': // HMAC
|
||||
Wl("Compute HMAC/SHA-256 digest from key + other info on device (HMAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_HMAC,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.hmac(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'm': // mac
|
||||
Wl("Compute SHA-256 from key + challenge + other info on device (MAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
Wl("Enter challenge (32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_MAC,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.mac(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'n': // nonce
|
||||
Wl("Generate a nonce for subsequent use by other commands (Nonce command).");
|
||||
Wl("Enter mode (00 to 03; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter input value (20 or 32 bytes (dep on mode); default all 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_NONCE, param1);
|
||||
Wl("none");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.nonce(tx_buffer,rx_buffer,param1,data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'r': // random
|
||||
Wl("Generate a random sequence.");
|
||||
Wl("Enter mode (00 or 01; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
print_execute_params(SHA204_RANDOM,param1);
|
||||
Wl("none");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.random(tx_buffer,rx_buffer,param1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'e': // read
|
||||
Wl("Read from device.");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data, +0x80 to read 32 instead of 4 bytes; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Address (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_READ,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.read(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'w': // write
|
||||
Wl("Write to device.");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data,");
|
||||
Wl(" +0x80 to write 32 instead of 4 bytes, +0x40 to require encryption; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Address (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
Wl("Enter data (4 or 32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
Wl("Enter MAC to validate address and data (0 or 32 bytes; default 0):");
|
||||
memset((void *)data2, 0, 32);
|
||||
get_bytes_serial(data2, 32);
|
||||
print_execute_params(SHA204_WRITE,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint_noln(data1, 32);
|
||||
W("data2 ");
|
||||
hexprint(data2, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.write(tx_buffer, rx_buffer, param1, param2, data1, data2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'u': // update_extra
|
||||
Wl("Update 'UserExtra' bytes (84 and 85) in the Conf zone after locking.");
|
||||
Wl("Enter mode (1 byte: 00->update 84, 01->update 85; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter new value (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
print_execute_params(SHA204_UPDATE_EXTRA,param1);
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.update_extra(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'k': // wake
|
||||
Wl("Test waking up.");
|
||||
print_executing();
|
||||
r = sha204.wakeup(rx_buffer);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
Wl("Should receive: 04 11 33 43");
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'L': // lock
|
||||
Wl("Lock a zone. This is a one time thing! Once you lock a zone, it CAN'T BE UNLOCKED. EVER!");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP_or_Data, +0x80 for 'force' (CRC ignored); default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Summary / CRC-16 of the zone (2 bytes, should be 0 if 'force'; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_LOCK,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.lock(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case '\r': // enter
|
||||
case '?': // help
|
||||
print_help();
|
||||
break;
|
||||
case 'I': // switch idle and sleep
|
||||
W("Switching whether the ATSHA should be put to sleep or to idle mode after commands.\n\rCurrent setting: ");
|
||||
if(idle) {
|
||||
idle = 0;
|
||||
Wl("Sleep.");
|
||||
}
|
||||
else {
|
||||
idle = 1;
|
||||
Wl("Idle.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions implementation */
|
||||
|
||||
void hexprint_byte(uint8_t b) {
|
||||
uint8_t high, low;
|
||||
low = b & 0xF;
|
||||
high = b >> 4;
|
||||
usb_serial_putchar(high+'0'+7*(high/10));
|
||||
usb_serial_putchar(low+'0'+7*(low/10));
|
||||
}
|
||||
|
||||
void hexprint_byte_sep(uint8_t b) {
|
||||
hexprint_byte(b);
|
||||
usb_serial_putchar(hexprint_separator);
|
||||
}
|
||||
|
||||
void hexprint_noln(uint8_t *p, uint16_t length) {
|
||||
for(uint16_t i=0; i<length; i++) {
|
||||
hexprint_byte(p[i]);
|
||||
if(hexprint_separator!=0)
|
||||
usb_serial_putchar(hexprint_separator);
|
||||
}
|
||||
}
|
||||
|
||||
void hexprint(uint8_t *p, uint16_t length) {
|
||||
hexprint_noln(p, length);
|
||||
usb_serial_write_P(PSTR("\n\r"));
|
||||
}
|
||||
|
||||
void hexprint_4bits(uint8_t b) {
|
||||
usb_serial_putchar((b&0xF)+'0'+7*((b&0xF)/10));
|
||||
}
|
||||
|
||||
void hexprint_1bit(uint8_t b) {
|
||||
usb_serial_putchar((b&1)+'0');
|
||||
}
|
||||
|
||||
void print_help(void) {
|
||||
Wl("*** SHA204 playground [(c) 2014 flabbergast] ***\n\r");
|
||||
Wl("Raw commands: wa[k]e [c]heckMAC [d]erive_key dev_re[v]ision [g]en_dig [h]MAC");
|
||||
Wl(" [m]ac [n]once [r]andom r[e]ad [w]rite [u]date_extra");
|
||||
Wl("Processed commands: [s]erial c[o]nfig_zone");
|
||||
Wl("Playground config: [I]dle-or-sleep");
|
||||
Wl("'?' -> this help");
|
||||
Wl("Dangerous/one-time only! [L]ock\n\r");
|
||||
Wl("Additional comments:");
|
||||
Wl(" - Format of ATSHA204 command responses:");
|
||||
Wl(" <1byte:packet_size> <msg_byte> <msg_byte> ... <1byte:crc_1> <1byte:crc_2>");
|
||||
Wl(" - ATSHA204 is sent to sleep or to idle mode after every command, select via [I].");
|
||||
Wl(" - The 'sent packet' info does not always match what's actually exactly sent. It's provided");
|
||||
Wl(" mainly to check the entered parameters.");
|
||||
Wl(" - Input, when requested, is expected in (padded) HEX format, e.g. 'AB01' for two bytes: 171 1.\n\r");
|
||||
}
|
||||
|
||||
void print_executing(void) {
|
||||
W("Executing: ");
|
||||
}
|
||||
|
||||
void print_received_from_sha(uint8_t *rx_buffer) {
|
||||
W("Received from ATSHA204: ");
|
||||
hexprint(rx_buffer, rx_buffer[0]);
|
||||
}
|
||||
|
||||
void print_execute_params(uint8_t opcode, uint8_t param1) {
|
||||
W("Will run with: opcode ");
|
||||
hexprint_byte_sep(opcode);
|
||||
W("param1 ");
|
||||
hexprint_byte_sep(param1);
|
||||
W("param2 ");
|
||||
}
|
||||
|
||||
uint8_t get_bytes_serial(uint8_t *output, uint16_t len) {
|
||||
char buffer[2*MAX_BUFFER_SIZE];
|
||||
uint16_t input_length;
|
||||
uint16_t i;
|
||||
uint8_t low, high;
|
||||
|
||||
input_length = usb_serial_readline(buffer, 2*len+1, false);
|
||||
strupr(buffer);
|
||||
for(i=0; i<input_length; i+=2) {
|
||||
high = buffer[i] - '0';
|
||||
if(high > 9)
|
||||
high -= 7;
|
||||
low = buffer[i+1] - '0';
|
||||
if(low > 9)
|
||||
low -= 7;
|
||||
output[i/2] = (uint8_t)(low + (high << 4));
|
||||
}
|
||||
|
||||
return (input_length/2);
|
||||
}
|
||||
|
||||
/* Read and Interpret ATSHA204 configuration */
|
||||
void process_config(uint8_t *config) {
|
||||
// serial number
|
||||
W("Serial number: ");
|
||||
hexprint_noln(config+ADDRESS_SN03, 4);
|
||||
hexprint(config+ADDRESS_SN47, 5);
|
||||
// revision number
|
||||
W("Revision number: ");
|
||||
hexprint(config+ADDRESS_RevNum,4);
|
||||
// I2C setup
|
||||
if(config[ADDRESS_I2CEN]&1) {
|
||||
W("I2C enabled; Address: ");
|
||||
hexprint_byte(config[ADDRESS_I2CADD]>>1);
|
||||
W("\n\r");
|
||||
} else {
|
||||
W("SingleWire (I2C disabled); TTL input level: ");
|
||||
if(config[ADDRESS_I2CADD]&0b1000)
|
||||
Wl("Vcc");
|
||||
else
|
||||
Wl("fixed");
|
||||
}
|
||||
// OTP mode
|
||||
W("OTP mode: ");
|
||||
switch(config[ADDRESS_OTPMODE]) {
|
||||
case 0xAA:
|
||||
Wl("read-only");
|
||||
break;
|
||||
case 0x55:
|
||||
Wl("consumption");
|
||||
break;
|
||||
case 0x00:
|
||||
Wl("legacy");
|
||||
break;
|
||||
default:
|
||||
Wl("reserved value (problem!)");
|
||||
break;
|
||||
}
|
||||
// selector mode
|
||||
W("Selector: ");
|
||||
if(!config[ADDRESS_SELECTOR])
|
||||
Wl("can be updated with UpdateExtra.");
|
||||
else
|
||||
Wl("can be updated only if it is 0.");
|
||||
// User extra
|
||||
W("User Extra byte: ");
|
||||
hexprint_byte(config[84]);
|
||||
W("\n\r");
|
||||
// Selector
|
||||
W("Selector byte: ");
|
||||
hexprint_byte(config[85]);
|
||||
W("\n\r");
|
||||
// Lock data
|
||||
W("Data and OTP zones are ");
|
||||
if(config[86]==0x55)
|
||||
Wl("unlocked.");
|
||||
else
|
||||
Wl("locked!");
|
||||
// Lock config
|
||||
W("Config zone is ");
|
||||
if(config[87]==0x55)
|
||||
Wl("unlocked.");
|
||||
else
|
||||
Wl("locked!");
|
||||
// Slots
|
||||
uint8_t i;
|
||||
Wl("Configurations of slots: ");
|
||||
for(i=0; i<16; i++) {
|
||||
uint8_t addr = 20+(2*i);
|
||||
W("Slot:");
|
||||
hexprint_4bits(i);
|
||||
W(" ReadKey:");
|
||||
hexprint_4bits(config[addr]); // getting the 2 config bytes LSB first
|
||||
W(" CheckOnly:");
|
||||
hexprint_1bit(config[addr]>>4);
|
||||
W(" SingleUse:");
|
||||
hexprint_1bit(config[addr]>>5);
|
||||
W(" EncryptRead:");
|
||||
hexprint_1bit(config[addr]>>6);
|
||||
W(" IsSecret:");
|
||||
hexprint_1bit(config[addr]>>7);
|
||||
W("\n\r WriteKey:");
|
||||
hexprint_4bits(config[addr+1]);
|
||||
W(" WriteConfig:");
|
||||
hexprint_4bits(config[addr+1]>>4);
|
||||
W("\n\r");
|
||||
if(i<8) { // slots 0-7 have extra data
|
||||
W(" UseFlag:");
|
||||
hexprint_byte(config[52+(2*i)]);
|
||||
W(" UpdateCount:");
|
||||
hexprint_byte(config[53+(2*i)]);
|
||||
W("\n\r");
|
||||
}
|
||||
if(i==15) { // slot15 has limit on usage
|
||||
W(" LastKeyUse: ");
|
||||
hexprint(config+68, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t receive_serial_binary_transaction(uint8_t *buffer, uint8_t len) {
|
||||
delay(100); // give the transmitting side the chance to push the rest through
|
||||
if( usb_serial_available() == 0 ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
uint8_t n_bytes = usb_serial_getchar();
|
||||
if( n_bytes >= len ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
buffer[0] = n_bytes;
|
||||
for(uint8_t i=1; i<=n_bytes; i++) {
|
||||
if( usb_serial_available() == 0 ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
buffer[i] = (uint8_t)usb_serial_getchar();
|
||||
delay(3);
|
||||
}
|
||||
return BINARY_TRANSACTION_OK;
|
||||
}
|
||||
|
||||
uint8_t binary_mode_transaction(uint8_t *data, uint8_t rxsize, uint8_t *rx_buffer, SHA204SWI *sha204) {
|
||||
uint8_t i = 0;
|
||||
uint8_t len;
|
||||
uint8_t idle;
|
||||
uint8_t opcode;
|
||||
uint8_t param1;
|
||||
uint16_t param2;
|
||||
uint8_t datalen1=0;
|
||||
uint8_t data1[32];
|
||||
uint8_t datalen2=0;
|
||||
uint8_t data2[32];
|
||||
uint8_t datalen3=0;
|
||||
uint8_t data3[14];
|
||||
// process the input packet
|
||||
len = data[0];
|
||||
idle = data[1];
|
||||
if(len<5)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
opcode = data[2];
|
||||
param1 = data[3];
|
||||
param2 = data[4] + 256*data[5];
|
||||
if(len>5) {
|
||||
if((datalen1=data[6]) > 32)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen1; i++)
|
||||
data1[i] = data[7+i];
|
||||
}
|
||||
if(len>6+datalen1) {
|
||||
if((datalen2=data[7+datalen1]) > 32)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen2; i++)
|
||||
data2[i] = data[8+datalen1+i];
|
||||
}
|
||||
if(len>7+datalen1+datalen2) {
|
||||
if((datalen3=data[8+datalen1+datalen2]) > 13)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen3; i++)
|
||||
data3[i] = data[9+datalen1+datalen2+i];
|
||||
}
|
||||
// run the transaction
|
||||
sha204->wakeup(data);
|
||||
i = sha204->execute(opcode, param1, param2,
|
||||
datalen1, data1, datalen2, data2, datalen3, data3,
|
||||
len, data, rxsize, rx_buffer);
|
||||
if(idle)
|
||||
sha204->idle();
|
||||
else
|
||||
sha204->sleep();
|
||||
if(i != SHA204_SUCCESS)
|
||||
return BINARY_TRANSACTION_EXECUTE_ERROR;
|
||||
return BINARY_TRANSACTION_OK;
|
||||
}
|
||||
|
||||
/* Return code stuff */
|
||||
|
||||
const char retcode_success[] PROGMEM = "Success.";
|
||||
const char retcode_parse_error[] PROGMEM = "Parse error.";
|
||||
const char retcode_cmd_fail[] PROGMEM = "Command execution error.";
|
||||
const char retcode_status_crc[] PROGMEM = "CRC error.";
|
||||
const char retcode_status_unknown[] PROGMEM = "Unknown error.";
|
||||
const char retcode_func_fail[] PROGMEM = "Couldn't execute due to wrong condition/state.";
|
||||
const char retcode_gen_fail[] PROGMEM = "Unspecified error.";
|
||||
const char retcode_bad_param[] PROGMEM = "Bad parameter.";
|
||||
const char retcode_invalid_id[] PROGMEM = "Invalid device ID.";
|
||||
const char retcode_invalid_size[] PROGMEM = "Out of range error.";
|
||||
const char retcode_bad_crc[] PROGMEM = "Bad CRC received.";
|
||||
const char retcode_rx_fail[] PROGMEM = "Timeout while waiting for a response (got >0 bytes).";
|
||||
const char retcode_rx_no_response[] PROGMEM = "Timeout (not an error while busy).";
|
||||
const char retcode_resync_with_wakeup[] PROGMEM = "Resync OK after wakeup.";
|
||||
const char retcode_comm_fail[] PROGMEM = "Communication failed";
|
||||
const char retcode_timeout[] PROGMEM = "Timeout while waiting for a response (got no bytes).";
|
||||
const char retcode_unknown[] PROGMEM = "Unknown error message.";
|
||||
|
||||
void print_return_code(uint8_t code) {
|
||||
const char *p PROGMEM;
|
||||
switch(code) {
|
||||
case(SHA204_SUCCESS):
|
||||
p = retcode_success;
|
||||
break;
|
||||
case(SHA204_PARSE_ERROR):
|
||||
p = retcode_parse_error;
|
||||
break;
|
||||
case(SHA204_CMD_FAIL):
|
||||
p = retcode_cmd_fail;
|
||||
break;
|
||||
case(SHA204_STATUS_CRC):
|
||||
p = retcode_status_crc;
|
||||
break;
|
||||
case(SHA204_STATUS_UNKNOWN):
|
||||
p = retcode_status_unknown;
|
||||
break;
|
||||
case(SHA204_FUNC_FAIL):
|
||||
p = retcode_func_fail;
|
||||
break;
|
||||
case(SHA204_GEN_FAIL):
|
||||
p = retcode_gen_fail;
|
||||
break;
|
||||
case(SHA204_BAD_PARAM):
|
||||
p = retcode_bad_param;
|
||||
break;
|
||||
case(SHA204_INVALID_ID):
|
||||
p = retcode_invalid_id;
|
||||
break;
|
||||
case(SHA204_INVALID_SIZE):
|
||||
p = retcode_invalid_size;
|
||||
break;
|
||||
case(SHA204_BAD_CRC):
|
||||
p = retcode_bad_crc;
|
||||
break;
|
||||
case(SHA204_RX_FAIL):
|
||||
p = retcode_rx_fail;
|
||||
break;
|
||||
case(SHA204_RX_NO_RESPONSE):
|
||||
p = retcode_rx_no_response;
|
||||
break;
|
||||
case(SHA204_RESYNC_WITH_WAKEUP):
|
||||
p = retcode_resync_with_wakeup;
|
||||
break;
|
||||
case(SHA204_COMM_FAIL):
|
||||
p = retcode_comm_fail;
|
||||
break;
|
||||
case(SHA204_TIMEOUT):
|
||||
p = retcode_timeout;
|
||||
break;
|
||||
default:
|
||||
p = retcode_unknown;
|
||||
break;
|
||||
}
|
||||
usb_serial_write_P(p);
|
||||
Serial.write("\n\r");
|
||||
}
|
||||
|
||||
// implementation of "LufaLayer"
|
||||
uint16_t usb_serial_available(void) {
|
||||
return Serial.available();
|
||||
}
|
||||
|
||||
int16_t usb_serial_getchar(void) {
|
||||
return Serial.read();
|
||||
}
|
||||
|
||||
void usb_serial_putchar(uint8_t ch) {
|
||||
Serial.write(ch);
|
||||
}
|
||||
|
||||
void usb_serial_write_P(PGM_P data) {
|
||||
for (uint8_t c; (c = pgm_read_byte(data)); data++) Serial.write(c);
|
||||
}
|
||||
|
||||
void usb_serial_write(const char* const buffer) {
|
||||
Serial.write(buffer);
|
||||
}
|
||||
|
||||
uint16_t usb_serial_readline(char *buffer, const uint16_t buffer_size, const bool obscure_input)
|
||||
{
|
||||
while(Serial.available() == 0) ;
|
||||
Serial.setTimeout(100);
|
||||
uint16_t r = Serial.readBytes(buffer, buffer_size);
|
||||
Serial.setTimeout(1000);
|
||||
return(r);
|
||||
}
|
||||
|
57
avr/Board/Board.h
Normal file
57
avr/Board/Board.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Board.h
|
||||
* (c) 2014 flabbergast
|
||||
* Custom Board definitions for use with LUFA, for AVR stick.
|
||||
*
|
||||
* Based on a template from LUFA library (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
#ifndef __BOARD_USER_H__
|
||||
#define __BOARD_USER_H__
|
||||
/* Includes: */
|
||||
// TODO: Add any required includes here
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Preprocessor Checks: */
|
||||
#if !defined(__INCLUDE_FROM_BOARD_H)
|
||||
#error Do not include this file directly. Include LUFA/Drivers/Board/Board.h instead.
|
||||
#endif
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
#define BOARD_HAS_BUTTONS
|
||||
// #define BOARD_HAS_DATAFLASH
|
||||
// #define BOARD_HAS_JOYSTICK
|
||||
// #define BOARD_HAS_LEDS
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
74
avr/Board/Buttons.h
Normal file
74
avr/Board/Buttons.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Buttons.h
|
||||
* (c) 2014 flabbergast
|
||||
* Custom Buttons definitions for use with LUFA, for AVR stick.
|
||||
*
|
||||
* Based on a template from LUFA library (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
#ifndef __BUTTONS_USER_H__
|
||||
#define __BUTTONS_USER_H__
|
||||
/* Includes: */
|
||||
// TODO: Add any required includes here
|
||||
#include <avr/io.h>
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Preprocessor Checks: */
|
||||
#if !defined(__INCLUDE_FROM_BUTTONS_H)
|
||||
#error Do not include this file directly. Include LUFA/Drivers/Board/Buttons.h instead.
|
||||
#endif
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
#define BUTTONS_BUTTON1 _BV(7)
|
||||
/* Inline Functions: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
static inline void Buttons_Init(void)
|
||||
{
|
||||
PORTF.DIRCLR = BUTTONS_BUTTON1;
|
||||
PORTF.PIN7CTRL = PORT_OPC_PULLUP_gc; // pull-up on pin 7
|
||||
}
|
||||
static inline void Buttons_Disable(void)
|
||||
{
|
||||
PORTF.PIN7CTRL = 0; // don't know what's the default state of pull-up/down?
|
||||
PORTF.DIRCLR = BUTTONS_BUTTON1;
|
||||
}
|
||||
static inline uint8_t Buttons_GetStatus(void) ATTR_WARN_UNUSED_RESULT;
|
||||
static inline uint8_t Buttons_GetStatus(void)
|
||||
{
|
||||
// TODO: Return current button status here, debounced if required
|
||||
return ((PORTF.IN & BUTTONS_BUTTON1) ^ BUTTONS_BUTTON1);
|
||||
}
|
||||
#endif
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
99
avr/Board/LEDs.h
Normal file
99
avr/Board/LEDs.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* LEDs.h
|
||||
* (c) 2014 flabbergast
|
||||
* Custom LEDs definitions for use with LUFA, for AVR stick.
|
||||
*
|
||||
* Based on a template from LUFA library (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
#ifndef __LEDS_USER_H__
|
||||
#define __LEDS_USER_H__
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
/* Enable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Preprocessor Checks: */
|
||||
#if !defined(__INCLUDE_FROM_LEDS_H)
|
||||
#error Do not include this file directly. Include LUFA/Drivers/Board/LEDS.h instead.
|
||||
#endif
|
||||
/* Public Interface - May be used in end-application: */
|
||||
/* Macros: */
|
||||
#define LEDS_LED1 (1 << 0)
|
||||
#define LEDS_LED2 (1 << 1)
|
||||
#define LEDS_LED3 (1 << 2)
|
||||
#define LEDS_LED4 (1 << 3)
|
||||
#define LEDS_ALL_LEDS (LEDS_LED1 | LEDS_LED2 | LEDS_LED3 | LEDS_LED4)
|
||||
#define LEDS_NO_LEDS 0
|
||||
/* Inline Functions: */
|
||||
#if !defined(__DOXYGEN__)
|
||||
static inline void LEDs_Init(void)
|
||||
{
|
||||
PORTE.DIRSET = LEDS_ALL_LEDS;
|
||||
PORTE.OUTCLR = LEDS_ALL_LEDS;
|
||||
}
|
||||
static inline void LEDs_Disable(void)
|
||||
{
|
||||
PORTE.DIRCLR = LEDS_ALL_LEDS;
|
||||
PORTE.OUTCLR = LEDS_ALL_LEDS;
|
||||
}
|
||||
static inline void LEDs_TurnOnLEDs(const uint8_t LEDMask)
|
||||
{
|
||||
PORTE.OUTSET = LEDMask & LEDS_ALL_LEDS;
|
||||
}
|
||||
static inline void LEDs_TurnOffLEDs(const uint8_t LEDMask)
|
||||
{
|
||||
PORTE.OUTCLR = LEDMask & LEDS_ALL_LEDS;
|
||||
}
|
||||
static inline void LEDs_SetAllLEDs(const uint8_t LEDMask)
|
||||
{
|
||||
PORTE.OUTCLR = LEDS_ALL_LEDS;
|
||||
PORTE.OUTSET = LEDMask & LEDS_ALL_LEDS;
|
||||
}
|
||||
static inline void LEDs_ChangeLEDs(const uint8_t LEDMask, const uint8_t ActiveMask)
|
||||
{
|
||||
PORTE.OUTCLR = (LEDMask & LEDS_ALL_LEDS);
|
||||
PORTE.OUTSET = (ActiveMask & LEDS_ALL_LEDS);
|
||||
}
|
||||
static inline void LEDs_ToggleLEDs(const uint8_t LEDMask)
|
||||
{
|
||||
PORTE.OUTTGL = (LEDMask & LEDS_ALL_LEDS);
|
||||
}
|
||||
static inline uint8_t LEDs_GetLEDs(void) ATTR_WARN_UNUSED_RESULT;
|
||||
static inline uint8_t LEDs_GetLEDs(void)
|
||||
{
|
||||
return ((PORTE.OUT & LEDS_ALL_LEDS));
|
||||
}
|
||||
#endif
|
||||
/* Disable C linkage for C++ Compilers: */
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
126
avr/Config/LUFAConfig.h
Normal file
126
avr/Config/LUFAConfig.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \brief LUFA Library Configuration Header File
|
||||
*
|
||||
* This header file is used to configure LUFA's compile time options,
|
||||
* as an alternative to the compile time constants supplied through
|
||||
* a makefile.
|
||||
*
|
||||
* For information on what each token does, refer to the LUFA
|
||||
* manual section "Summary of Compile Tokens".
|
||||
*/
|
||||
|
||||
#ifndef _LUFA_CONFIG_H_
|
||||
#define _LUFA_CONFIG_H_
|
||||
|
||||
#if (ARCH == ARCH_AVR8)
|
||||
|
||||
/* Non-USB Related Configuration Tokens: */
|
||||
// #define DISABLE_TERMINAL_CODES
|
||||
|
||||
/* USB Class Driver Related Tokens: */
|
||||
// #define HID_HOST_BOOT_PROTOCOL_ONLY
|
||||
// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_USAGE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_MAX_COLLECTIONS {Insert Value Here}
|
||||
// #define HID_MAX_REPORTITEMS {Insert Value Here}
|
||||
// #define HID_MAX_REPORT_IDS {Insert Value Here}
|
||||
// #define NO_CLASS_DRIVER_AUTOFLUSH
|
||||
|
||||
/* General USB Driver Related Tokens: */
|
||||
// #define ORDERED_EP_CONFIG
|
||||
#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)
|
||||
#define USB_DEVICE_ONLY
|
||||
// #define USB_HOST_ONLY
|
||||
// #define USB_STREAM_TIMEOUT_MS {Insert Value Here}
|
||||
// #define NO_LIMITED_CONTROLLER_CONNECT
|
||||
// #define NO_SOF_EVENTS
|
||||
|
||||
/* USB Device Mode Driver Related Tokens: */
|
||||
// #define USE_RAM_DESCRIPTORS
|
||||
#define USE_FLASH_DESCRIPTORS
|
||||
// #define USE_EEPROM_DESCRIPTORS
|
||||
// #define NO_INTERNAL_SERIAL
|
||||
#define FIXED_CONTROL_ENDPOINT_SIZE 8
|
||||
// #define DEVICE_STATE_AS_GPIOR {Insert Value Here}
|
||||
#define FIXED_NUM_CONFIGURATIONS 1
|
||||
// #define CONTROL_ONLY_DEVICE
|
||||
#define INTERRUPT_CONTROL_ENDPOINT
|
||||
// #define NO_DEVICE_REMOTE_WAKEUP
|
||||
// #define NO_DEVICE_SELF_POWER
|
||||
|
||||
/* USB Host Mode Driver Related Tokens: */
|
||||
// #define HOST_STATE_AS_GPIOR {Insert Value Here}
|
||||
// #define USB_HOST_TIMEOUT_MS {Insert Value Here}
|
||||
// #define HOST_DEVICE_SETTLE_DELAY_MS {Insert Value Here}
|
||||
// #define NO_AUTO_VBUS_MANAGEMENT
|
||||
// #define INVERTED_VBUS_ENABLE_LINE
|
||||
|
||||
#elif (ARCH == ARCH_XMEGA)
|
||||
|
||||
/* Non-USB Related Configuration Tokens: */
|
||||
// #define DISABLE_TERMINAL_CODES
|
||||
|
||||
/* USB Class Driver Related Tokens: */
|
||||
// #define HID_HOST_BOOT_PROTOCOL_ONLY
|
||||
// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_USAGE_STACK_DEPTH {Insert Value Here}
|
||||
// #define HID_MAX_COLLECTIONS {Insert Value Here}
|
||||
// #define HID_MAX_REPORTITEMS {Insert Value Here}
|
||||
// #define HID_MAX_REPORT_IDS {Insert Value Here}
|
||||
// #define NO_CLASS_DRIVER_AUTOFLUSH
|
||||
|
||||
/* General USB Driver Related Tokens: */
|
||||
#define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRIHIGH)
|
||||
// #define USB_STREAM_TIMEOUT_MS {Insert Value Here}
|
||||
// #define NO_LIMITED_CONTROLLER_CONNECT
|
||||
// #define NO_SOF_EVENTS
|
||||
|
||||
/* USB Device Mode Driver Related Tokens: */
|
||||
// #define USE_RAM_DESCRIPTORS
|
||||
#define USE_FLASH_DESCRIPTORS
|
||||
// #define USE_EEPROM_DESCRIPTORS
|
||||
// #define NO_INTERNAL_SERIAL
|
||||
#define FIXED_CONTROL_ENDPOINT_SIZE 8
|
||||
// #define DEVICE_STATE_AS_GPIOR {Insert Value Here}
|
||||
#define FIXED_NUM_CONFIGURATIONS 1
|
||||
// #define CONTROL_ONLY_DEVICE
|
||||
#define MAX_ENDPOINT_INDEX 4
|
||||
// #define NO_DEVICE_REMOTE_WAKEUP
|
||||
// #define NO_DEVICE_SELF_POWER
|
||||
|
||||
#else
|
||||
|
||||
#error Unsupported architecture for this LUFA configuration file.
|
||||
|
||||
#endif
|
||||
#endif
|
325
avr/Descriptors.c
Normal file
325
avr/Descriptors.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Descriptors.c
|
||||
* (c) 2014 flabbergast
|
||||
* USB Descriptors.
|
||||
* Most code comes from a LUFA library Demo (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* USB Device Descriptors, for library use when in USB device mode. Descriptors are special
|
||||
* computer-readable structures which the host requests upon device enumeration, to determine
|
||||
* the device's capabilities and functions.
|
||||
*/
|
||||
|
||||
#include "Descriptors.h"
|
||||
|
||||
|
||||
/** HID class report descriptor. This is a special descriptor constructed with values from the
|
||||
* USBIF HID class specification to describe the reports and capabilities of the HID device. This
|
||||
* descriptor is parsed by the host and its contents used to determine what data (and in what encoding)
|
||||
* the device will send, and what it may be sent back from the host. Refer to the HID specification for
|
||||
* more details on HID report descriptors.
|
||||
*/
|
||||
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
|
||||
{
|
||||
/* Use the HID class driver's standard Keyboard report.
|
||||
* Max simultaneous keys: 6
|
||||
*/
|
||||
HID_DESCRIPTOR_KEYBOARD(6)
|
||||
};
|
||||
|
||||
/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
|
||||
* device characteristics, including the supported USB version, control endpoint size and the
|
||||
* number of device configurations. The descriptor is read out by the USB host when the enumeration
|
||||
* process begins.
|
||||
*/
|
||||
const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
|
||||
|
||||
.USBSpecification = VERSION_BCD(1,1,0),
|
||||
.Class = USB_CSCP_IADDeviceClass,
|
||||
.SubClass = USB_CSCP_IADDeviceSubclass,
|
||||
.Protocol = USB_CSCP_IADDeviceProtocol,
|
||||
|
||||
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
|
||||
|
||||
.VendorID = 0x03EB,
|
||||
.ProductID = 0x206F,
|
||||
.ReleaseNumber = VERSION_BCD(0,0,1),
|
||||
|
||||
.ManufacturerStrIndex = STRING_ID_Manufacturer,
|
||||
.ProductStrIndex = STRING_ID_Product,
|
||||
.SerialNumStrIndex = USE_INTERNAL_SERIAL,
|
||||
|
||||
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
|
||||
};
|
||||
|
||||
/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
|
||||
* of the device in one of its supported configurations, including information about any device interfaces
|
||||
* and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
|
||||
* a configuration so that the host may correctly communicate with the USB device.
|
||||
*/
|
||||
const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration},
|
||||
|
||||
.TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t),
|
||||
.TotalInterfaces = 3,
|
||||
|
||||
.ConfigurationNumber = 1,
|
||||
.ConfigurationStrIndex = NO_DESCRIPTOR,
|
||||
|
||||
.ConfigAttributes = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED),
|
||||
|
||||
.MaxPowerConsumption = USB_CONFIG_POWER_MA(100)
|
||||
},
|
||||
|
||||
.CDC_IAD =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},
|
||||
|
||||
.FirstInterfaceIndex = INTERFACE_ID_CDC_CCI,
|
||||
.TotalInterfaces = 2,
|
||||
|
||||
.Class = CDC_CSCP_CDCClass,
|
||||
.SubClass = CDC_CSCP_ACMSubclass,
|
||||
.Protocol = CDC_CSCP_ATCommandProtocol,
|
||||
|
||||
.IADStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.CDC_CCI_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_CDC_CCI,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = CDC_CSCP_CDCClass,
|
||||
.SubClass = CDC_CSCP_ACMSubclass,
|
||||
.Protocol = CDC_CSCP_ATCommandProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.CDC_Functional_Header =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = CDC_DSUBTYPE_CSInterface_Header,
|
||||
|
||||
.CDCSpecification = VERSION_BCD(1,1,0),
|
||||
},
|
||||
|
||||
.CDC_Functional_ACM =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = CDC_DSUBTYPE_CSInterface_ACM,
|
||||
|
||||
.Capabilities = 0x06,
|
||||
},
|
||||
|
||||
.CDC_Functional_Union =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface},
|
||||
.Subtype = CDC_DSUBTYPE_CSInterface_Union,
|
||||
|
||||
.MasterInterfaceNumber = INTERFACE_ID_CDC_CCI,
|
||||
.SlaveInterfaceNumber = INTERFACE_ID_CDC_DCI,
|
||||
},
|
||||
|
||||
.CDC_NotificationEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = CDC_NOTIFICATION_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = CDC_NOTIFICATION_EPSIZE,
|
||||
.PollingIntervalMS = 0xFF
|
||||
},
|
||||
|
||||
.CDC_DCI_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_CDC_DCI,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 2,
|
||||
|
||||
.Class = CDC_CSCP_CDCDataClass,
|
||||
.SubClass = CDC_CSCP_NoDataSubclass,
|
||||
.Protocol = CDC_CSCP_NoDataProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.CDC_DataOutEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = CDC_RX_EPADDR,
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = CDC_TXRX_EPSIZE,
|
||||
.PollingIntervalMS = 0x05
|
||||
},
|
||||
|
||||
.CDC_DataInEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = CDC_TX_EPADDR,
|
||||
.Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = CDC_TXRX_EPSIZE,
|
||||
.PollingIntervalMS = 0x05
|
||||
},
|
||||
|
||||
.HID_Interface =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
|
||||
|
||||
.InterfaceNumber = INTERFACE_ID_Keyboard,
|
||||
.AlternateSetting = 0,
|
||||
|
||||
.TotalEndpoints = 1,
|
||||
|
||||
.Class = HID_CSCP_HIDClass,
|
||||
.SubClass = HID_CSCP_BootSubclass,
|
||||
.Protocol = HID_CSCP_KeyboardBootProtocol,
|
||||
|
||||
.InterfaceStrIndex = NO_DESCRIPTOR
|
||||
},
|
||||
|
||||
.HID_KeyboardHID =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID},
|
||||
|
||||
.HIDSpec = VERSION_BCD(1,1,1),
|
||||
.CountryCode = 0x00,
|
||||
.TotalReportDescriptors = 1,
|
||||
.HIDReportType = HID_DTYPE_Report,
|
||||
.HIDReportLength = sizeof(KeyboardReport)
|
||||
},
|
||||
|
||||
.HID_ReportINEndpoint =
|
||||
{
|
||||
.Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
|
||||
|
||||
.EndpointAddress = KEYBOARD_EPADDR,
|
||||
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
|
||||
.EndpointSize = KEYBOARD_EPSIZE,
|
||||
.PollingIntervalMS = 0x05
|
||||
}
|
||||
};
|
||||
|
||||
/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests
|
||||
* the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate
|
||||
* via the language ID table available at USB.org what languages the device supports for its string descriptors.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM LanguageString = USB_STRING_DESCRIPTOR_ARRAY(LANGUAGE_ID_ENG);
|
||||
|
||||
/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable
|
||||
* form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR(L"flabbergast");
|
||||
|
||||
/** Product descriptor string. This is a Unicode string containing the product's details in human readable form,
|
||||
* and is read out upon request by the host when the appropriate string ID is requested, listed in the Device
|
||||
* Descriptor.
|
||||
*/
|
||||
const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"serial/keyboard AVR stick dev demo");
|
||||
|
||||
/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors"
|
||||
* documentation) by the application code so that the address and size of a requested descriptor can be given
|
||||
* to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function
|
||||
* is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the
|
||||
* USB host.
|
||||
*/
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
{
|
||||
const uint8_t DescriptorType = (wValue >> 8);
|
||||
const uint8_t DescriptorNumber = (wValue & 0xFF);
|
||||
|
||||
const void* Address = NULL;
|
||||
uint16_t Size = NO_DESCRIPTOR;
|
||||
|
||||
switch (DescriptorType)
|
||||
{
|
||||
case DTYPE_Device:
|
||||
Address = &DeviceDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Device_t);
|
||||
break;
|
||||
case DTYPE_Configuration:
|
||||
Address = &ConfigurationDescriptor;
|
||||
Size = sizeof(USB_Descriptor_Configuration_t);
|
||||
break;
|
||||
case DTYPE_String:
|
||||
switch (DescriptorNumber)
|
||||
{
|
||||
case STRING_ID_Language:
|
||||
Address = &LanguageString;
|
||||
Size = pgm_read_byte(&LanguageString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_Manufacturer:
|
||||
Address = &ManufacturerString;
|
||||
Size = pgm_read_byte(&ManufacturerString.Header.Size);
|
||||
break;
|
||||
case STRING_ID_Product:
|
||||
Address = &ProductString;
|
||||
Size = pgm_read_byte(&ProductString.Header.Size);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case HID_DTYPE_HID:
|
||||
Address = &ConfigurationDescriptor.HID_KeyboardHID;
|
||||
Size = sizeof(USB_HID_Descriptor_HID_t);
|
||||
break;
|
||||
case HID_DTYPE_Report:
|
||||
Address = &KeyboardReport;
|
||||
Size = sizeof(KeyboardReport);
|
||||
break;
|
||||
}
|
||||
|
||||
*DescriptorAddress = Address;
|
||||
return Size;
|
||||
}
|
||||
|
130
avr/Descriptors.h
Normal file
130
avr/Descriptors.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Descriptors.h
|
||||
* (c) 2014 flabbergast
|
||||
* USB Descriptors.
|
||||
* Most code comes from a LUFA library Demo (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for Descriptors.c.
|
||||
*/
|
||||
|
||||
#ifndef _DESCRIPTORS_H_
|
||||
#define _DESCRIPTORS_H_
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
|
||||
/* Macros: */
|
||||
/** Endpoint address of the CDC device-to-host notification IN endpoint. */
|
||||
#define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2)
|
||||
|
||||
/** Endpoint address of the CDC device-to-host data IN endpoint. */
|
||||
#define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3)
|
||||
|
||||
/** Endpoint address of the CDC host-to-device data OUT endpoint. */
|
||||
#define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4)
|
||||
|
||||
/** Size in bytes of the CDC device-to-host notification IN endpoint. */
|
||||
#define CDC_NOTIFICATION_EPSIZE 8
|
||||
|
||||
/** Size in bytes of the CDC data IN and OUT endpoints. */
|
||||
#define CDC_TXRX_EPSIZE 16
|
||||
|
||||
/** Endpoint address of the Keyboard HID reporting IN endpoint. */
|
||||
#define KEYBOARD_EPADDR (ENDPOINT_DIR_IN | 1)
|
||||
|
||||
/** Size in bytes of the Keyboard HID reporting IN endpoint. */
|
||||
#define KEYBOARD_EPSIZE 8
|
||||
|
||||
/* Type Defines: */
|
||||
/** Type define for the device configuration descriptor structure. This must be defined in the
|
||||
* application code, as the configuration descriptor contains several sub-descriptors which
|
||||
* vary between devices, and which describe the device's usage to the host.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
USB_Descriptor_Configuration_Header_t Config;
|
||||
|
||||
// CDC Control Interface
|
||||
USB_Descriptor_Interface_Association_t CDC_IAD;
|
||||
USB_Descriptor_Interface_t CDC_CCI_Interface;
|
||||
USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header;
|
||||
USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM;
|
||||
USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union;
|
||||
USB_Descriptor_Endpoint_t CDC_NotificationEndpoint;
|
||||
|
||||
// CDC Data Interface
|
||||
USB_Descriptor_Interface_t CDC_DCI_Interface;
|
||||
USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
|
||||
USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
|
||||
|
||||
// Keyboard HID Interface
|
||||
USB_Descriptor_Interface_t HID_Interface;
|
||||
USB_HID_Descriptor_HID_t HID_KeyboardHID;
|
||||
USB_Descriptor_Endpoint_t HID_ReportINEndpoint;
|
||||
} USB_Descriptor_Configuration_t;
|
||||
|
||||
/** Enum for the device interface descriptor IDs within the device. Each interface descriptor
|
||||
* should have a unique ID index associated with it, which can be used to refer to the
|
||||
* interface from other descriptors.
|
||||
*/
|
||||
enum InterfaceDescriptors_t
|
||||
{
|
||||
INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */
|
||||
INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */
|
||||
INTERFACE_ID_Keyboard = 2, /**< Keyboard interface descriptor ID */
|
||||
};
|
||||
|
||||
/** Enum for the device string descriptor IDs within the device. Each string descriptor should
|
||||
* have a unique ID index associated with it, which can be used to refer to the string from
|
||||
* other descriptors.
|
||||
*/
|
||||
enum StringDescriptors_t
|
||||
{
|
||||
STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */
|
||||
STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */
|
||||
STRING_ID_Product = 2, /**< Product string ID */
|
||||
};
|
||||
|
||||
/* Function Prototypes: */
|
||||
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
|
||||
const uint8_t wIndex,
|
||||
const void** const DescriptorAddress)
|
||||
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);
|
||||
|
||||
#endif
|
||||
|
414
avr/LufaLayer.c
Normal file
414
avr/LufaLayer.c
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* LufaLayer.c
|
||||
* (c) 2014 flabbergast
|
||||
* USB and Board layer: provides "easy-to-use" functions for
|
||||
* the main program code.
|
||||
*
|
||||
* Portions of code come from a LUFA library Demo (license below).
|
||||
*/
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
#include "LufaLayer.h"
|
||||
|
||||
/* Includes: */
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Descriptors.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Platform/Platform.h>
|
||||
|
||||
|
||||
/** LUFA CDC Class driver interface configuration and state information. This structure is
|
||||
* passed to all CDC Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.ControlInterfaceNumber = INTERFACE_ID_CDC_CCI,
|
||||
.DataINEndpoint =
|
||||
{
|
||||
.Address = CDC_TX_EPADDR,
|
||||
.Size = CDC_TXRX_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.DataOUTEndpoint =
|
||||
{
|
||||
.Address = CDC_RX_EPADDR,
|
||||
.Size = CDC_TXRX_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.NotificationEndpoint =
|
||||
{
|
||||
.Address = CDC_NOTIFICATION_EPADDR,
|
||||
.Size = CDC_NOTIFICATION_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/** Buffer to hold the previously generated Keyboard HID report, for comparison purposes inside the HID class driver. */
|
||||
static uint8_t PrevKeyboardHIDReportBuffer[sizeof(USB_KeyboardReport_Data_t)];
|
||||
|
||||
/** LUFA HID Class driver interface configuration and state information. This structure is
|
||||
* passed to all HID Class driver functions, so that multiple instances of the same class
|
||||
* within a device can be differentiated from one another.
|
||||
*/
|
||||
USB_ClassInfo_HID_Device_t Keyboard_HID_Interface =
|
||||
{
|
||||
.Config =
|
||||
{
|
||||
.InterfaceNumber = INTERFACE_ID_Keyboard,
|
||||
.ReportINEndpoint =
|
||||
{
|
||||
.Address = KEYBOARD_EPADDR,
|
||||
.Size = KEYBOARD_EPSIZE,
|
||||
.Banks = 1,
|
||||
},
|
||||
.PrevReportINBuffer = PrevKeyboardHIDReportBuffer,
|
||||
.PrevReportINBufferSize = sizeof(PrevKeyboardHIDReportBuffer),
|
||||
},
|
||||
};
|
||||
|
||||
/* by flabbergast:
|
||||
* implementation of exported functions
|
||||
* ** basic functions **
|
||||
*/
|
||||
void init(void)
|
||||
{
|
||||
SetupHardware();
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
GlobalInterruptEnable();
|
||||
}
|
||||
|
||||
void usb_tasks(void)
|
||||
{
|
||||
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
|
||||
HID_Device_USBTask(&Keyboard_HID_Interface);
|
||||
USB_USBTask();
|
||||
}
|
||||
|
||||
/*
|
||||
* ** usb_serial **
|
||||
*/
|
||||
|
||||
uint16_t usb_serial_available(void)
|
||||
{
|
||||
return CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
||||
int16_t usb_serial_getchar(void)
|
||||
{
|
||||
return CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
||||
void usb_serial_wait_for_key(void)
|
||||
{
|
||||
while(usb_serial_available() == 0) {
|
||||
usb_tasks();
|
||||
service_button();
|
||||
_delay_ms(10);
|
||||
}
|
||||
}
|
||||
|
||||
void usb_serial_flush_input(void)
|
||||
{
|
||||
int16_t i;
|
||||
int16_t bufsize = CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface);
|
||||
for(i=0; i<bufsize; i++)
|
||||
CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
||||
void usb_serial_putchar(uint8_t ch)
|
||||
{
|
||||
CDC_Device_SendByte(&VirtualSerial_CDC_Interface, ch);
|
||||
}
|
||||
|
||||
void usb_serial_write(const char* const buffer)
|
||||
{
|
||||
CDC_Device_SendString(&VirtualSerial_CDC_Interface, buffer);
|
||||
}
|
||||
|
||||
void usb_serial_write_P(const char* data)
|
||||
{
|
||||
while(pgm_read_byte(data) != 0)
|
||||
usb_serial_putchar(pgm_read_byte(data++));
|
||||
}
|
||||
|
||||
void usb_serial_writeln(const char* const buffer)
|
||||
{
|
||||
CDC_Device_SendString(&VirtualSerial_CDC_Interface, buffer);
|
||||
usb_serial_write_P(PSTR("\r\n"));
|
||||
}
|
||||
|
||||
void usb_serial_writeln_P(const char* data)
|
||||
{
|
||||
usb_serial_write_P(data);
|
||||
usb_serial_write_P(PSTR("\r\n"));
|
||||
}
|
||||
|
||||
void usb_serial_flush_output(void)
|
||||
{
|
||||
CDC_Device_Flush(&VirtualSerial_CDC_Interface);
|
||||
}
|
||||
|
||||
void usb_serial_readline_refresh(const char *buffer, const uint16_t n, const bool obscure_input)
|
||||
{
|
||||
uint16_t i;
|
||||
// delete the previous stuff on the line (plus one extra space)
|
||||
usb_serial_putchar('\r');
|
||||
for(i=0; i<=n; i++)
|
||||
usb_serial_putchar(' ');
|
||||
// write out the buffer contents
|
||||
usb_serial_putchar('\r');
|
||||
for(i=0; i<n; i++)
|
||||
if(obscure_input)
|
||||
usb_serial_putchar('*');
|
||||
else
|
||||
usb_serial_putchar(buffer[i]);
|
||||
}
|
||||
|
||||
uint16_t usb_serial_readline(char *buffer, const uint16_t buffer_size, const bool obscure_input)
|
||||
{
|
||||
uint16_t end = 0;
|
||||
char c;
|
||||
|
||||
while(true) {
|
||||
if(usb_serial_available() > 0) {
|
||||
c = (char)usb_serial_getchar();
|
||||
switch((char) c) {
|
||||
case '\r': // enter
|
||||
buffer[end] = 0;
|
||||
usb_serial_putchar('\n');
|
||||
usb_serial_putchar('\r');
|
||||
return end;
|
||||
break;
|
||||
case '\b': // ^H
|
||||
case 127: // backspace
|
||||
end--;
|
||||
usb_serial_write("\b \b"); // remove the last char from the display
|
||||
//usb_serial_readline_refresh(buffer, end, obscure_input);
|
||||
break;
|
||||
default:
|
||||
if(end < buffer_size-1) {
|
||||
buffer[end++] = c;
|
||||
if(obscure_input)
|
||||
usb_serial_putchar('*');
|
||||
else
|
||||
usb_serial_putchar(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
usb_tasks();
|
||||
service_button();
|
||||
_delay_ms(10);
|
||||
}
|
||||
return 0; // never reached
|
||||
}
|
||||
|
||||
bool usb_serial_dtr(void) {
|
||||
return(VirtualSerial_CDC_Interface.State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR);
|
||||
}
|
||||
|
||||
/** Configures the board hardware and chip peripherals for the demo's functionality. */
|
||||
void SetupHardware(void)
|
||||
{
|
||||
#if (ARCH == ARCH_AVR8)
|
||||
/* Disable watchdog if enabled by bootloader/fuses */
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
wdt_disable();
|
||||
|
||||
/* Disable clock division */
|
||||
clock_prescale_set(clock_div_1);
|
||||
#elif (ARCH == ARCH_XMEGA)
|
||||
/* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */
|
||||
XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU);
|
||||
XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL);
|
||||
|
||||
/* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */
|
||||
XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ);
|
||||
XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB);
|
||||
|
||||
PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
|
||||
#endif
|
||||
|
||||
/* Hardware Initialization */
|
||||
LEDs_Init();
|
||||
Buttons_Init();
|
||||
USB_Init();
|
||||
Timer_Init();
|
||||
}
|
||||
|
||||
/*
|
||||
* ** button **
|
||||
*/
|
||||
|
||||
bool button_is_pressed = false;
|
||||
uint32_t button_pressed_timestamp = 0;
|
||||
|
||||
/** Checks for the button state */
|
||||
void service_button(void)
|
||||
{
|
||||
uint8_t ButtonStatus_LCL = Buttons_GetStatus();
|
||||
|
||||
if (ButtonStatus_LCL & BUTTONS_BUTTON1) {
|
||||
if (! button_is_pressed) {
|
||||
button_pressed_timestamp = millis10();
|
||||
button_is_pressed = true;
|
||||
}
|
||||
} else {
|
||||
button_is_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** returns for how long was the button pressed, in 10/1024 ms */
|
||||
uint32_t button_pressed_for(void) {
|
||||
if(button_is_pressed)
|
||||
return (millis10() - button_pressed_timestamp);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Connection event. */
|
||||
void EVENT_USB_Device_Connect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Disconnection event. */
|
||||
void EVENT_USB_Device_Disconnect(void)
|
||||
{
|
||||
LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Configuration Changed event. */
|
||||
void EVENT_USB_Device_ConfigurationChanged(void)
|
||||
{
|
||||
bool ConfigSuccess = true;
|
||||
|
||||
ConfigSuccess &= HID_Device_ConfigureEndpoints(&Keyboard_HID_Interface);
|
||||
ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
|
||||
|
||||
USB_Device_EnableSOFEvents();
|
||||
|
||||
LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
|
||||
}
|
||||
|
||||
/** Event handler for the library USB Control Request reception event. */
|
||||
void EVENT_USB_Device_ControlRequest(void)
|
||||
{
|
||||
CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
|
||||
HID_Device_ProcessControlRequest(&Keyboard_HID_Interface);
|
||||
}
|
||||
|
||||
/** Event handler for the USB device Start Of Frame event. */
|
||||
void EVENT_USB_Device_StartOfFrame(void)
|
||||
{
|
||||
HID_Device_MillisecondElapsed(&Keyboard_HID_Interface);
|
||||
}
|
||||
|
||||
/* by flabbergast:
|
||||
* global variables used for the HID callback below
|
||||
*/
|
||||
uint8_t usb_keyboard_current_key_GLOBAL = 0;
|
||||
uint8_t usb_keyboard_current_modifier_GLOBAL = 0;
|
||||
bool usb_keyboard_send_current_data_GLOBAL = false;
|
||||
|
||||
/** HID class driver callback function for the creation of HID reports to the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in,out] ReportID Report ID requested by the host if non-zero, otherwise callback should set to the generated report ID
|
||||
* \param[in] ReportType Type of the report to create, either HID_REPORT_ITEM_In or HID_REPORT_ITEM_Feature
|
||||
* \param[out] ReportData Pointer to a buffer where the created report should be stored
|
||||
* \param[out] ReportSize Number of bytes written in the report (or zero if no report is to be sent)
|
||||
*
|
||||
* \return Boolean \c true to force the sending of the report, \c false to let the library determine if it needs to be sent
|
||||
*/
|
||||
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
uint8_t* const ReportID,
|
||||
const uint8_t ReportType,
|
||||
void* ReportData,
|
||||
uint16_t* const ReportSize)
|
||||
{
|
||||
USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
|
||||
if (usb_keyboard_send_current_data_GLOBAL)
|
||||
{
|
||||
KeyboardReport->KeyCode[0] = usb_keyboard_current_key_GLOBAL;
|
||||
KeyboardReport->Modifier = usb_keyboard_current_modifier_GLOBAL;
|
||||
usb_keyboard_send_current_data_GLOBAL = false;
|
||||
}
|
||||
*ReportSize = sizeof(USB_KeyboardReport_Data_t);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* by flabbergast:
|
||||
* usb_keyboard_press(key, mod)
|
||||
* set global variables to let the above callback generate a keypress
|
||||
* returns 'true' if data is set; 'false' when the previous keypress wasn't sent yet
|
||||
*/
|
||||
bool usb_keyboard_press(uint8_t key, uint8_t modifier) {
|
||||
if(usb_keyboard_send_current_data_GLOBAL)
|
||||
return false;
|
||||
usb_keyboard_current_key_GLOBAL = key;
|
||||
usb_keyboard_current_modifier_GLOBAL = modifier;
|
||||
usb_keyboard_send_current_data_GLOBAL = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** HID class driver callback function for the processing of HID reports from the host.
|
||||
*
|
||||
* \param[in] HIDInterfaceInfo Pointer to the HID class interface configuration structure being referenced
|
||||
* \param[in] ReportID Report ID of the received report from the host
|
||||
* \param[in] ReportType The type of report that the host has sent, either HID_REPORT_ITEM_Out or HID_REPORT_ITEM_Feature
|
||||
* \param[in] ReportData Pointer to a buffer where the received report has been stored
|
||||
* \param[in] ReportSize Size in bytes of the received HID report
|
||||
*/
|
||||
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
const uint8_t ReportType,
|
||||
const void* ReportData,
|
||||
const uint16_t ReportSize)
|
||||
{
|
||||
// Unused (but mandatory for the HID class driver) in this demo, since there are no Host->Device reports
|
||||
}
|
||||
|
120
avr/LufaLayer.h
Normal file
120
avr/LufaLayer.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* LufaLayer.h
|
||||
* (c) 2014 flabbergast
|
||||
* USB and Board layer: header file.
|
||||
* See below the #includes for a list of functions provided by this
|
||||
* layer.
|
||||
*
|
||||
* Portions of code come from a LUFA library Demo (license below).
|
||||
*/
|
||||
|
||||
#ifndef _LUFALAYER_H_
|
||||
#define _LUFALAYER_H_
|
||||
|
||||
/*
|
||||
LUFA Library
|
||||
Copyright (C) Dean Camera, 2014.
|
||||
|
||||
dean [at] fourwalledcubicle [dot] com
|
||||
www.lufa-lib.org
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2014 Dean Camera (dean [at] fourwalledcubicle [dot] com)
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this
|
||||
software and its documentation for any purpose is hereby granted
|
||||
without fee, provided that the above copyright notice appear in
|
||||
all copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of the author not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
|
||||
The author disclaims all warranties with regard to this
|
||||
software, including all implied warranties of merchantability
|
||||
and fitness. In no event shall the author be liable for any
|
||||
special, indirect or consequential damages or any damages
|
||||
whatsoever resulting from loss of use, data or profits, whether
|
||||
in an action of contract, negligence or other tortious action,
|
||||
arising out of or in connection with the use or performance of
|
||||
this software.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
*
|
||||
* Header file for LufaLayer.c.
|
||||
*/
|
||||
|
||||
/* Includes: */
|
||||
#include <LUFA/Drivers/Board/LEDs.h>
|
||||
#include <LUFA/Drivers/Board/Buttons.h>
|
||||
#include <LUFA/Drivers/USB/USB.h>
|
||||
#include <LUFA/Platform/Platform.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
/* by flabbergast: exported functions to be used in the main program code
|
||||
*/
|
||||
// basic functions
|
||||
void init(void);
|
||||
void usb_tasks(void);
|
||||
// usb_serial
|
||||
uint16_t usb_serial_available(void); // number of getchars guaranteed to succeed immediately
|
||||
int16_t usb_serial_getchar(void); // negative values mean error in receiving (not connected or no input)
|
||||
void usb_serial_flush_input(void);
|
||||
void usb_serial_putchar(uint8_t ch);
|
||||
void usb_serial_wait_for_key(void); // BLOCKING (takes care of _tasks)
|
||||
void usb_serial_write(const char* const buffer);
|
||||
void usb_serial_write_P(const char* data);
|
||||
void usb_serial_writeln(const char* const buffer);
|
||||
void usb_serial_writeln_P(const char* data);
|
||||
void usb_serial_flush_output(void);
|
||||
uint16_t usb_serial_readline(char *buffer, const uint16_t buffer_size, const bool obscure_input); // BLOCKING (takes care of _tasks)
|
||||
bool usb_serial_dtr(void);
|
||||
// usb_keyboard
|
||||
bool usb_keyboard_press(uint8_t key, uint8_t mod);
|
||||
// buttons, LEDs and such
|
||||
uint32_t button_pressed_for(void); // for how long was the button pressed? (in 10/1024 sec; 0 if not pressed)
|
||||
void service_button(void); // should be called periodically to update the button state
|
||||
|
||||
/* Macros: */
|
||||
/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
|
||||
#define LEDMASK_USB_NOTREADY LEDS_LED1
|
||||
|
||||
/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
|
||||
#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
|
||||
|
||||
/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
|
||||
#define LEDMASK_USB_READY (LEDS_LED2 | LEDS_LED4)
|
||||
|
||||
/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
|
||||
#define LEDMASK_USB_ERROR (LEDS_LED1 | LEDS_LED3)
|
||||
|
||||
/* Function Prototypes: */
|
||||
void SetupHardware(void);
|
||||
|
||||
void EVENT_USB_Device_Connect(void);
|
||||
void EVENT_USB_Device_Disconnect(void);
|
||||
void EVENT_USB_Device_ConfigurationChanged(void);
|
||||
void EVENT_USB_Device_ControlRequest(void);
|
||||
void EVENT_USB_Device_StartOfFrame(void);
|
||||
|
||||
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
uint8_t* const ReportID,
|
||||
const uint8_t ReportType,
|
||||
void* ReportData,
|
||||
uint16_t* const ReportSize);
|
||||
void CALLBACK_HID_Device_ProcessHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
|
||||
const uint8_t ReportID,
|
||||
const uint8_t ReportType,
|
||||
const void* ReportData,
|
||||
const uint16_t ReportSize);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
75
avr/README.md
Normal file
75
avr/README.md
Normal file
|
@ -0,0 +1,75 @@
|
|||
# sha204_playground firmware: straight avr-gcc version
|
||||
|
||||
Here are the source for the sha204_playground firmware, to be compiled
|
||||
with avr-gcc against the [LUFA] library.
|
||||
|
||||
## Compilation / usage
|
||||
|
||||
Get the [LUFA] library and copy the `LUFA` folder to the subdirectory
|
||||
`avr/LUFA`.
|
||||
|
||||
Make modifications to match your hardware setup (`makefile` and
|
||||
`SHA204/SHA204SWI_hardware_config.h` are probably the most important
|
||||
ones).
|
||||
|
||||
Compile (`make`) and upload to your board with ATSHA204 (how to do this
|
||||
depends on your bootloader).
|
||||
|
||||
After reset, your board should enumerate as a CDC Serial Device (also as
|
||||
a keyboard, but that functionality isn't used yet). Note that an `.inf`
|
||||
file might be required on Windows systems.
|
||||
|
||||
Connect to this Serial device using a serial terminal (e.g. puTTY,
|
||||
picocom, minicom, screen, ...) and you should be presented with a "menu"
|
||||
of commands that interact with ATSHA204 device.
|
||||
|
||||
## Communicating with the firmware
|
||||
|
||||
Probably the first thing to try is pressing `k` (to test waking the
|
||||
ATSHA up) and pressing `s` (to print the serial number of your device).
|
||||
|
||||
Alternatively (depending on the functionality required), you can use the
|
||||
`talk_to_sha204.py` script to talk to the ATSHA via this firmware.
|
||||
|
||||
### Binary mode
|
||||
|
||||
The firmware supports a "binary mode", for use with scripts. For a
|
||||
demonstration on how this is done, have a look at the python script
|
||||
`talk_to_sha204.py`.
|
||||
|
||||
## Notes
|
||||
|
||||
- The subdirectory `SHA204` contains a re-usable library, working on
|
||||
both AVR8 and XMEGA architectures. Note that only 16MHz and 32MHz CPU
|
||||
speeds are tested.
|
||||
- At the moment, only Single-Wire Interface for ATSHA204 is implemented,
|
||||
by bit-banging in C (so a speedy CPU is probably required).
|
||||
- The firmware also enumerates as a Keyboard. This functionality is not
|
||||
used at the moment; see `LufaLayer.h` for the functions that can
|
||||
generate "keypresses".
|
||||
|
||||
## VID/PID
|
||||
|
||||
Every USB device has a Vendor/Product identifying signature. This is set
|
||||
in software here (`Descriptors.c`). The current code uses a pair which
|
||||
belongs to the [LUFA] library. DO NOT USE IT for any other than
|
||||
development purposes only! See [LUFA's VID/PID
|
||||
page](http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__v_i_d_p_i_d.html).
|
||||
|
||||
## Credits
|
||||
|
||||
- The whole USB interface utilizes Dean Camera's excellent [LUFA]
|
||||
library, and builds on several LUFA demos supplied with the library.
|
||||
- I've started with bettse's version of a SHA204 library for Arduino
|
||||
[on github](https://github.com/bettse/arduino_projects/tree/master/libraries/SHA204),
|
||||
and modified it to work on XMEGA firmware, and not necessarily as an
|
||||
Arduino library.
|
||||
|
||||
## License
|
||||
|
||||
My code is (c) flabbergast. MIT license (see LICENSE file). Portions
|
||||
of the code come from LUFA demos, this is licensed by LUFA's license.
|
||||
The original code from SHA204 library is licensed by Apache V2.0 license.
|
||||
|
||||
|
||||
[LUFA]: http://www.fourwalledcubicle.com/LUFA.php
|
11
avr/SHA204/README.md
Normal file
11
avr/SHA204/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
SHA204 Library
|
||||
==============
|
||||
|
||||
This is the main SHA204 library for the ATSHA204 chip from Atmel.
|
||||
|
||||
In order to use it you will need to copy this directory to a
|
||||
subdirectory of your project, include `SHA204SWI.h` and instantiate a
|
||||
`SHA204SWI` object.
|
||||
|
||||
Note that you'll need to modify the `SHA204SWI_hardware_config.h` to
|
||||
match your hardware setup (the wiring is hardcoded during compilation!).
|
795
avr/SHA204/SHA204.cpp
Normal file
795
avr/SHA204/SHA204.cpp
Normal file
|
@ -0,0 +1,795 @@
|
|||
/*
|
||||
Copyright 2013 Nusku Networks
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SHA204.h"
|
||||
#include "SHA204ReturnCodes.h"
|
||||
#include "SHA204Definitions.h"
|
||||
#include <util/delay.h>
|
||||
#include <string.h>
|
||||
|
||||
// helper function to make delay work with variable delay
|
||||
void Delay_ms(uint32_t n) {
|
||||
while (n--)
|
||||
_delay_ms(1);
|
||||
}
|
||||
|
||||
|
||||
/* Puts a the ATSHA204's unique, 4-byte serial number in the response array
|
||||
returns an SHA204 Return code */
|
||||
uint8_t SHA204::serialNumber(uint8_t * response) {
|
||||
uint8_t readCommand[READ_COUNT];
|
||||
uint8_t readResponse[READ_4_RSP_SIZE];
|
||||
|
||||
/* read from bytes 0->3 of config zone */
|
||||
uint8_t returnCode = read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03);
|
||||
if (!returnCode) // should return 0 if successful
|
||||
{
|
||||
for (int i=0; i<4; i++) // store bytes 0-3 into respones array
|
||||
response[i] = readResponse[SHA204_BUFFER_POS_DATA+i];
|
||||
|
||||
/* read from bytes 8->11 of config zone */
|
||||
returnCode = read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47);
|
||||
|
||||
for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array
|
||||
response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)];
|
||||
|
||||
if (!returnCode)
|
||||
{ /* Finally if last two reads were successful, read byte 8 of the SN */
|
||||
returnCode = read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8);
|
||||
response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE
|
||||
}
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
/* Communication functions */
|
||||
|
||||
uint8_t SHA204::wakeup(uint8_t *response) {
|
||||
uint8_t ret_code = chip_wakeup();
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
return ret_code;
|
||||
|
||||
ret_code = receive_response(SHA204_RSP_SIZE_MIN, response);
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
return ret_code;
|
||||
|
||||
// Verify status response.
|
||||
if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN)
|
||||
ret_code = SHA204_INVALID_SIZE;
|
||||
else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP)
|
||||
ret_code = SHA204_COMM_FAIL;
|
||||
else
|
||||
{
|
||||
if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33)
|
||||
|| (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43))
|
||||
ret_code = SHA204_BAD_CRC;
|
||||
}
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
_delay_ms(SHA204_COMMAND_EXEC_MAX);
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
uint8_t SHA204::send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) {
|
||||
uint8_t ret_code = SHA204_FUNC_FAIL;
|
||||
uint8_t ret_code_resync;
|
||||
uint8_t n_retries_send;
|
||||
uint8_t n_retries_receive;
|
||||
uint8_t i;
|
||||
uint8_t status_byte;
|
||||
uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT];
|
||||
uint8_t count_minus_crc = count - SHA204_CRC_SIZE;
|
||||
uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT();
|
||||
volatile uint16_t timeout_countdown;
|
||||
|
||||
// Append CRC.
|
||||
calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc);
|
||||
|
||||
// Retry loop for sending a command and receiving a response.
|
||||
n_retries_send = SHA204_RETRY_COUNT + 1;
|
||||
|
||||
while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS))
|
||||
{
|
||||
// Send command.
|
||||
ret_code = send_command(count, tx_buffer);
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
{
|
||||
if (resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
|
||||
return ret_code; // The device seems to be dead in the water.
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait minimum command execution time and then start polling for a response.
|
||||
Delay_ms(execution_delay);
|
||||
|
||||
// Retry loop for receiving a response.
|
||||
n_retries_receive = SHA204_RETRY_COUNT + 1;
|
||||
while (n_retries_receive-- > 0)
|
||||
{
|
||||
// Reset response buffer.
|
||||
for (i = 0; i < rx_size; i++)
|
||||
rx_buffer[i] = 0;
|
||||
|
||||
// Poll for response.
|
||||
timeout_countdown = execution_timeout_us;
|
||||
do
|
||||
{
|
||||
ret_code = receive_response(rx_size, rx_buffer);
|
||||
timeout_countdown -= SHA204_RESPONSE_TIMEOUT();
|
||||
}
|
||||
while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT()) && (ret_code == SHA204_RX_NO_RESPONSE));
|
||||
|
||||
if (ret_code == SHA204_RX_NO_RESPONSE)
|
||||
{
|
||||
// We did not receive a response. Re-synchronize and send command again.
|
||||
if (resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
|
||||
// The device seems to be dead in the water.
|
||||
return ret_code;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Check whether we received a valid response.
|
||||
if (ret_code == SHA204_INVALID_SIZE)
|
||||
{
|
||||
// We see 0xFF for the count when communication got out of sync.
|
||||
ret_code_resync = resync(rx_size, rx_buffer);
|
||||
if (ret_code_resync == SHA204_SUCCESS)
|
||||
// We did not have to wake up the device. Try receiving response again.
|
||||
continue;
|
||||
if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP)
|
||||
// We could re-synchronize, but only after waking up the device.
|
||||
// Re-send command.
|
||||
break;
|
||||
else
|
||||
// We failed to re-synchronize.
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// We received a response of valid size.
|
||||
// Check the consistency of the response.
|
||||
ret_code = check_crc(rx_buffer);
|
||||
if (ret_code == SHA204_SUCCESS)
|
||||
{
|
||||
// Received valid response.
|
||||
if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN)
|
||||
// Received non-status response. We are done.
|
||||
return ret_code;
|
||||
|
||||
// Received status response.
|
||||
status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS];
|
||||
|
||||
// Translate the three possible device status error codes
|
||||
// into library return codes.
|
||||
if (status_byte == SHA204_STATUS_BYTE_PARSE)
|
||||
return SHA204_PARSE_ERROR;
|
||||
if (status_byte == SHA204_STATUS_BYTE_EXEC)
|
||||
return SHA204_CMD_FAIL;
|
||||
if (status_byte == SHA204_STATUS_BYTE_COMM)
|
||||
{
|
||||
// In case of the device status byte indicating a communication
|
||||
// error this function exits the retry loop for receiving a response
|
||||
// and enters the overall retry loop
|
||||
// (send command / receive response).
|
||||
ret_code = SHA204_STATUS_CRC;
|
||||
break;
|
||||
}
|
||||
|
||||
// Received status response from CheckMAC, DeriveKey, GenDig,
|
||||
// Lock, Nonce, Pause, UpdateExtra, or Write command.
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Received response with incorrect CRC.
|
||||
ret_code_resync = resync(rx_size, rx_buffer);
|
||||
if (ret_code_resync == SHA204_SUCCESS)
|
||||
// We did not have to wake up the device. Try receiving response again.
|
||||
continue;
|
||||
if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP)
|
||||
// We could re-synchronize, but only after waking up the device.
|
||||
// Re-send command.
|
||||
break;
|
||||
else
|
||||
// We failed to re-synchronize.
|
||||
return ret_code;
|
||||
} // block end of check response consistency
|
||||
|
||||
} // block end of receive retry loop
|
||||
|
||||
} // block end of send and receive retry loop
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
|
||||
/* Marshaling functions */
|
||||
|
||||
uint8_t SHA204::random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode) {
|
||||
if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM;
|
||||
tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE;
|
||||
|
||||
tx_buffer[RANDOM_PARAM2_IDX] =
|
||||
tx_buffer[RANDOM_PARAM2_IDX + 1] = 0;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer) {
|
||||
if (!tx_buffer || !rx_buffer)
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV;
|
||||
|
||||
// Parameters are 0.
|
||||
tx_buffer[DEVREV_PARAM1_IDX] =
|
||||
tx_buffer[DEVREV_PARAM2_IDX] =
|
||||
tx_buffer[DEVREV_PARAM2_IDX + 1] = 0;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0],
|
||||
DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) {
|
||||
uint8_t rx_size;
|
||||
|
||||
if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0)
|
||||
|| ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP)))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
address >>= 2;
|
||||
if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG)
|
||||
{
|
||||
if (address > SHA204_ADDRESS_MASK_CONFIG)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP)
|
||||
{
|
||||
if (address > SHA204_ADDRESS_MASK_OTP)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA)
|
||||
{
|
||||
if (address > SHA204_ADDRESS_MASK)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = READ_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ;
|
||||
tx_buffer[READ_ZONE_IDX] = zone;
|
||||
tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK);
|
||||
tx_buffer[READ_ADDR_IDX + 1] = 0;
|
||||
|
||||
rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::execute(uint8_t op_code, uint8_t param1, uint16_t param2,
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
|
||||
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) {
|
||||
uint8_t poll_delay, poll_timeout, response_size;
|
||||
uint8_t *p_buffer;
|
||||
uint8_t len;
|
||||
|
||||
uint8_t ret_code = check_parameters(op_code, param1, param2,
|
||||
datalen1, data1, datalen2, data2, datalen3, data3,
|
||||
tx_size, tx_buffer, rx_size, rx_buffer);
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
return ret_code;
|
||||
|
||||
// Supply delays and response size.
|
||||
switch (op_code)
|
||||
{
|
||||
case SHA204_CHECKMAC:
|
||||
poll_delay = CHECKMAC_DELAY;
|
||||
poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY;
|
||||
response_size = CHECKMAC_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_DERIVE_KEY:
|
||||
poll_delay = DERIVE_KEY_DELAY;
|
||||
poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY;
|
||||
response_size = DERIVE_KEY_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_DEVREV:
|
||||
poll_delay = DEVREV_DELAY;
|
||||
poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY;
|
||||
response_size = DEVREV_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_GENDIG:
|
||||
poll_delay = GENDIG_DELAY;
|
||||
poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY;
|
||||
response_size = GENDIG_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_HMAC:
|
||||
poll_delay = HMAC_DELAY;
|
||||
poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY;
|
||||
response_size = HMAC_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_LOCK:
|
||||
poll_delay = LOCK_DELAY;
|
||||
poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY;
|
||||
response_size = LOCK_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_MAC:
|
||||
poll_delay = MAC_DELAY;
|
||||
poll_timeout = MAC_EXEC_MAX - MAC_DELAY;
|
||||
response_size = MAC_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_NONCE:
|
||||
poll_delay = NONCE_DELAY;
|
||||
poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY;
|
||||
response_size = param1 == NONCE_MODE_PASSTHROUGH
|
||||
? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG;
|
||||
break;
|
||||
|
||||
case SHA204_PAUSE:
|
||||
poll_delay = PAUSE_DELAY;
|
||||
poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY;
|
||||
response_size = PAUSE_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_RANDOM:
|
||||
poll_delay = RANDOM_DELAY;
|
||||
poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY;
|
||||
response_size = RANDOM_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_READ:
|
||||
poll_delay = READ_DELAY;
|
||||
poll_timeout = READ_EXEC_MAX - READ_DELAY;
|
||||
response_size = (param1 & SHA204_ZONE_COUNT_FLAG)
|
||||
? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_UPDATE_EXTRA:
|
||||
poll_delay = UPDATE_DELAY;
|
||||
poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY;
|
||||
response_size = UPDATE_RSP_SIZE;
|
||||
break;
|
||||
|
||||
case SHA204_WRITE:
|
||||
poll_delay = WRITE_DELAY;
|
||||
poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY;
|
||||
response_size = WRITE_RSP_SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
poll_delay = 0;
|
||||
poll_timeout = SHA204_COMMAND_EXEC_MAX;
|
||||
response_size = rx_size;
|
||||
}
|
||||
|
||||
// Assemble command.
|
||||
len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN;
|
||||
p_buffer = tx_buffer;
|
||||
*p_buffer++ = len;
|
||||
*p_buffer++ = op_code;
|
||||
*p_buffer++ = param1;
|
||||
*p_buffer++ = param2 & 0xFF;
|
||||
*p_buffer++ = param2 >> 8;
|
||||
|
||||
if (datalen1 > 0) {
|
||||
memcpy(p_buffer, data1, datalen1);
|
||||
p_buffer += datalen1;
|
||||
}
|
||||
if (datalen2 > 0) {
|
||||
memcpy(p_buffer, data2, datalen2);
|
||||
p_buffer += datalen2;
|
||||
}
|
||||
if (datalen3 > 0) {
|
||||
memcpy(p_buffer, data3, datalen3);
|
||||
p_buffer += datalen3;
|
||||
}
|
||||
|
||||
calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer);
|
||||
|
||||
// Send command and receive response.
|
||||
return send_and_receive(&tx_buffer[0], response_size,
|
||||
&rx_buffer[0], poll_delay, poll_timeout);
|
||||
}
|
||||
|
||||
uint8_t SHA204::check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2,
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
|
||||
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) {
|
||||
#ifdef SHA204_CHECK_PARAMETERS
|
||||
|
||||
uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN;
|
||||
if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer)
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
// Check parameters depending on op-code.
|
||||
switch (op_code)
|
||||
{
|
||||
case SHA204_CHECKMAC:
|
||||
if (
|
||||
// no null pointers allowed
|
||||
!data1 || !data2
|
||||
// No reserved bits should be set.
|
||||
|| (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK
|
||||
// key_id > 15 not allowed
|
||||
|| param2 > SHA204_KEY_ID_MAX
|
||||
)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_DERIVE_KEY:
|
||||
if (param2 > SHA204_KEY_ID_MAX)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_DEVREV:
|
||||
break;
|
||||
|
||||
case SHA204_GENDIG:
|
||||
if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA))
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_HMAC:
|
||||
if ((param1 & ~HMAC_MODE_MASK) != 0)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_LOCK:
|
||||
if (((param1 & ~LOCK_ZONE_MASK) != 0)
|
||||
|| ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0)))
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_MAC:
|
||||
if (((param1 & ~MAC_MODE_MASK) != 0)
|
||||
|| (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1))
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_NONCE:
|
||||
if ( !data1
|
||||
|| (param1 > NONCE_MODE_PASSTHROUGH)
|
||||
|| (param1 == NONCE_MODE_INVALID)
|
||||
)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_PAUSE:
|
||||
break;
|
||||
|
||||
case SHA204_RANDOM:
|
||||
if (param1 > RANDOM_NO_SEED_UPDATE)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_READ:
|
||||
if (((param1 & ~READ_ZONE_MASK) != 0)
|
||||
|| ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP)))
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_TEMPSENSE:
|
||||
break;
|
||||
|
||||
case SHA204_UPDATE_EXTRA:
|
||||
if (param1 > UPDATE_CONFIG_BYTE_86)
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
case SHA204_WRITE:
|
||||
if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0))
|
||||
return SHA204_BAD_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
// unknown op-code
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
|
||||
return SHA204_SUCCESS;
|
||||
|
||||
#else
|
||||
return SHA204_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* CRC Calculator and Checker */
|
||||
|
||||
void SHA204::calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) {
|
||||
uint8_t counter;
|
||||
uint16_t crc_register = 0;
|
||||
uint16_t polynom = 0x8005;
|
||||
uint8_t shift_register;
|
||||
uint8_t data_bit, crc_bit;
|
||||
|
||||
for (counter = 0; counter < length; counter++)
|
||||
{
|
||||
for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1)
|
||||
{
|
||||
data_bit = (data[counter] & shift_register) ? 1 : 0;
|
||||
crc_bit = crc_register >> 15;
|
||||
|
||||
// Shift CRC to the left by 1.
|
||||
crc_register <<= 1;
|
||||
|
||||
if ((data_bit ^ crc_bit) != 0)
|
||||
crc_register ^= polynom;
|
||||
}
|
||||
}
|
||||
crc[0] = (uint8_t) (crc_register & 0x00FF);
|
||||
crc[1] = (uint8_t) (crc_register >> 8);
|
||||
}
|
||||
|
||||
uint8_t SHA204::check_crc(uint8_t *response) {
|
||||
uint8_t crc[SHA204_CRC_SIZE];
|
||||
uint8_t count = response[SHA204_BUFFER_POS_COUNT];
|
||||
|
||||
count -= SHA204_CRC_SIZE;
|
||||
calculate_crc(count, response, crc);
|
||||
|
||||
return (crc[0] == response[count] && crc[1] == response[count + 1])
|
||||
? SHA204_SUCCESS : SHA204_BAD_CRC;
|
||||
}
|
||||
|
||||
uint8_t SHA204::check_mac(uint8_t *tx_buffer, uint8_t *rx_buffer,
|
||||
uint8_t mode, uint8_t key_id, uint8_t *client_challenge, uint8_t *client_response, uint8_t *other_data) {
|
||||
if (
|
||||
// no null pointers allowed
|
||||
!tx_buffer || !rx_buffer || !client_response || !other_data
|
||||
// No reserved bits should be set.
|
||||
|| (mode | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK
|
||||
// key_id > 15 not allowed
|
||||
|| key_id > SHA204_KEY_ID_MAX
|
||||
)
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = CHECKMAC_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_CHECKMAC;
|
||||
tx_buffer[CHECKMAC_MODE_IDX] = mode & CHECKMAC_MODE_MASK;
|
||||
tx_buffer[CHECKMAC_KEYID_IDX]= key_id;
|
||||
tx_buffer[CHECKMAC_KEYID_IDX + 1] = 0;
|
||||
if (client_challenge == NULL)
|
||||
memset(&tx_buffer[CHECKMAC_CLIENT_CHALLENGE_IDX], 0, CHECKMAC_CLIENT_CHALLENGE_SIZE);
|
||||
else
|
||||
memcpy(&tx_buffer[CHECKMAC_CLIENT_CHALLENGE_IDX], client_challenge, CHECKMAC_CLIENT_CHALLENGE_SIZE);
|
||||
|
||||
memcpy(&tx_buffer[CHECKMAC_CLIENT_RESPONSE_IDX], client_response, CHECKMAC_CLIENT_RESPONSE_SIZE);
|
||||
memcpy(&tx_buffer[CHECKMAC_DATA_IDX], other_data, CHECKMAC_OTHER_DATA_SIZE);
|
||||
|
||||
return send_and_receive(&tx_buffer[0], CHECKMAC_RSP_SIZE, &rx_buffer[0],
|
||||
CHECKMAC_DELAY, CHECKMAC_EXEC_MAX - CHECKMAC_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::derive_key(uint8_t *tx_buffer, uint8_t *rx_buffer,
|
||||
uint8_t random, uint8_t target_key, uint8_t *mac) {
|
||||
if (!tx_buffer || !rx_buffer || ((random & ~DERIVE_KEY_RANDOM_FLAG) != 0)
|
||||
|| (target_key > SHA204_KEY_ID_MAX))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_DERIVE_KEY;
|
||||
tx_buffer[DERIVE_KEY_RANDOM_IDX] = random;
|
||||
tx_buffer[DERIVE_KEY_TARGETKEY_IDX] = target_key;
|
||||
tx_buffer[DERIVE_KEY_TARGETKEY_IDX + 1] = 0;
|
||||
if (mac != NULL)
|
||||
{
|
||||
memcpy(&tx_buffer[DERIVE_KEY_MAC_IDX], mac, DERIVE_KEY_MAC_SIZE);
|
||||
tx_buffer[SHA204_COUNT_IDX] = DERIVE_KEY_COUNT_LARGE;
|
||||
}
|
||||
else
|
||||
tx_buffer[SHA204_COUNT_IDX] = DERIVE_KEY_COUNT_SMALL;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], DERIVE_KEY_RSP_SIZE, &rx_buffer[0],
|
||||
DERIVE_KEY_DELAY, DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::gen_dig(uint8_t *tx_buffer, uint8_t *rx_buffer,
|
||||
uint8_t zone, uint8_t key_id, uint8_t *other_data) {
|
||||
if (!tx_buffer || !rx_buffer || (zone > GENDIG_ZONE_DATA))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
if (((zone == GENDIG_ZONE_OTP) && (key_id > SHA204_OTP_BLOCK_MAX))
|
||||
|| ((zone == GENDIG_ZONE_DATA) && (key_id > SHA204_KEY_ID_MAX)))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_GENDIG;
|
||||
tx_buffer[GENDIG_ZONE_IDX] = zone;
|
||||
tx_buffer[GENDIG_KEYID_IDX] = key_id;
|
||||
tx_buffer[GENDIG_KEYID_IDX + 1] = 0;
|
||||
if (other_data != NULL)
|
||||
{
|
||||
memcpy(&tx_buffer[GENDIG_DATA_IDX], other_data, GENDIG_OTHER_DATA_SIZE);
|
||||
tx_buffer[SHA204_COUNT_IDX] = GENDIG_COUNT_DATA;
|
||||
}
|
||||
else
|
||||
tx_buffer[SHA204_COUNT_IDX] = GENDIG_COUNT;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], GENDIG_RSP_SIZE, &rx_buffer[0],
|
||||
GENDIG_DELAY, GENDIG_EXEC_MAX - GENDIG_DELAY);
|
||||
|
||||
}
|
||||
|
||||
uint8_t SHA204::hmac(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint16_t key_id) {
|
||||
if (!tx_buffer || !rx_buffer || ((mode & ~HMAC_MODE_MASK) != 0))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = HMAC_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_HMAC;
|
||||
tx_buffer[HMAC_MODE_IDX] = mode;
|
||||
|
||||
// Although valid key identifiers are only
|
||||
// from 0 to 15, all 16 bits are used in the HMAC message.
|
||||
tx_buffer[HMAC_KEYID_IDX] = key_id & 0xFF;
|
||||
tx_buffer[HMAC_KEYID_IDX + 1] = key_id >> 8;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], HMAC_RSP_SIZE, &rx_buffer[0],
|
||||
HMAC_DELAY, HMAC_EXEC_MAX - HMAC_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::lock(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t summary) {
|
||||
if (!tx_buffer || !rx_buffer || ((zone & ~LOCK_ZONE_MASK) != 0)
|
||||
|| ((zone & LOCK_ZONE_NO_CRC) && (summary != 0)))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = LOCK_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_LOCK;
|
||||
tx_buffer[LOCK_ZONE_IDX] = zone & LOCK_ZONE_MASK;
|
||||
tx_buffer[LOCK_SUMMARY_IDX]= summary & 0xFF;
|
||||
tx_buffer[LOCK_SUMMARY_IDX + 1]= summary >> 8;
|
||||
return send_and_receive(&tx_buffer[0], LOCK_RSP_SIZE, &rx_buffer[0],
|
||||
LOCK_DELAY, LOCK_EXEC_MAX - LOCK_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::mac(uint8_t *tx_buffer, uint8_t *rx_buffer,
|
||||
uint8_t mode, uint16_t key_id, uint8_t *challenge) {
|
||||
if (!tx_buffer || !rx_buffer || ((mode & ~MAC_MODE_MASK) != 0)
|
||||
|| (((mode & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !challenge))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = MAC_COUNT_SHORT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_MAC;
|
||||
tx_buffer[MAC_MODE_IDX] = mode;
|
||||
tx_buffer[MAC_KEYID_IDX] = key_id & 0xFF;
|
||||
tx_buffer[MAC_KEYID_IDX + 1] = key_id >> 8;
|
||||
if ((mode & MAC_MODE_BLOCK2_TEMPKEY) == 0)
|
||||
{
|
||||
memcpy(&tx_buffer[MAC_CHALLENGE_IDX], challenge, MAC_CHALLENGE_SIZE);
|
||||
tx_buffer[SHA204_COUNT_IDX] = MAC_COUNT_LONG;
|
||||
}
|
||||
|
||||
return send_and_receive(&tx_buffer[0], MAC_RSP_SIZE, &rx_buffer[0],
|
||||
MAC_DELAY, MAC_EXEC_MAX - MAC_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::nonce(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint8_t *numin) {
|
||||
uint8_t rx_size;
|
||||
|
||||
if (!tx_buffer || !rx_buffer || !numin
|
||||
|| (mode > NONCE_MODE_PASSTHROUGH) || (mode == NONCE_MODE_INVALID))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_NONCE;
|
||||
tx_buffer[NONCE_MODE_IDX] = mode;
|
||||
|
||||
// 2. parameter is 0.
|
||||
tx_buffer[NONCE_PARAM2_IDX] =
|
||||
tx_buffer[NONCE_PARAM2_IDX + 1] = 0;
|
||||
|
||||
if (mode != NONCE_MODE_PASSTHROUGH)
|
||||
{
|
||||
memcpy(&tx_buffer[NONCE_INPUT_IDX], numin, NONCE_NUMIN_SIZE);
|
||||
tx_buffer[SHA204_COUNT_IDX] = NONCE_COUNT_SHORT;
|
||||
rx_size = NONCE_RSP_SIZE_LONG;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&tx_buffer[NONCE_INPUT_IDX], numin, NONCE_NUMIN_SIZE_PASSTHROUGH);
|
||||
tx_buffer[SHA204_COUNT_IDX] = NONCE_COUNT_LONG;
|
||||
rx_size = NONCE_RSP_SIZE_SHORT;
|
||||
}
|
||||
|
||||
return send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0],
|
||||
NONCE_DELAY, NONCE_EXEC_MAX - NONCE_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::pause(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t selector) {
|
||||
if (!tx_buffer || !rx_buffer)
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = PAUSE_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_PAUSE;
|
||||
tx_buffer[PAUSE_SELECT_IDX] = selector;
|
||||
|
||||
// 2. parameter is 0.
|
||||
tx_buffer[PAUSE_PARAM2_IDX] =
|
||||
tx_buffer[PAUSE_PARAM2_IDX + 1] = 0;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], PAUSE_RSP_SIZE, &rx_buffer[0],
|
||||
PAUSE_DELAY, PAUSE_EXEC_MAX - PAUSE_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::update_extra(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint8_t new_value) {
|
||||
if (!tx_buffer || !rx_buffer || (mode > UPDATE_CONFIG_BYTE_86))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
tx_buffer[SHA204_COUNT_IDX] = UPDATE_COUNT;
|
||||
tx_buffer[SHA204_OPCODE_IDX] = SHA204_UPDATE_EXTRA;
|
||||
tx_buffer[UPDATE_MODE_IDX] = mode;
|
||||
tx_buffer[UPDATE_VALUE_IDX] = new_value;
|
||||
tx_buffer[UPDATE_VALUE_IDX + 1] = 0;
|
||||
|
||||
return send_and_receive(&tx_buffer[0], UPDATE_RSP_SIZE, &rx_buffer[0],
|
||||
UPDATE_DELAY, UPDATE_EXEC_MAX - UPDATE_DELAY);
|
||||
}
|
||||
|
||||
uint8_t SHA204::write(uint8_t *tx_buffer, uint8_t *rx_buffer,
|
||||
uint8_t zone, uint16_t address, uint8_t *new_value, uint8_t *mac) {
|
||||
uint8_t *p_command;
|
||||
uint8_t count;
|
||||
|
||||
if (!tx_buffer || !rx_buffer || !new_value || ((zone & ~WRITE_ZONE_MASK) != 0))
|
||||
return SHA204_BAD_PARAM;
|
||||
|
||||
address >>= 2;
|
||||
if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) {
|
||||
if (address > SHA204_ADDRESS_MASK_CONFIG)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) {
|
||||
if (address > SHA204_ADDRESS_MASK_OTP)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) {
|
||||
if (address > SHA204_ADDRESS_MASK)
|
||||
return SHA204_BAD_PARAM;
|
||||
}
|
||||
|
||||
p_command = &tx_buffer[SHA204_OPCODE_IDX];
|
||||
*p_command++ = SHA204_WRITE;
|
||||
*p_command++ = zone;
|
||||
*p_command++ = (uint8_t) (address & SHA204_ADDRESS_MASK);
|
||||
*p_command++ = 0;
|
||||
|
||||
count = (zone & SHA204_ZONE_COUNT_FLAG) ? SHA204_ZONE_ACCESS_32 : SHA204_ZONE_ACCESS_4;
|
||||
memcpy(p_command, new_value, count);
|
||||
p_command += count;
|
||||
|
||||
if (mac != NULL)
|
||||
{
|
||||
memcpy(p_command, mac, WRITE_MAC_SIZE);
|
||||
p_command += WRITE_MAC_SIZE;
|
||||
}
|
||||
|
||||
// Supply count.
|
||||
tx_buffer[SHA204_COUNT_IDX] = (uint8_t) (p_command - &tx_buffer[0] + SHA204_CRC_SIZE);
|
||||
|
||||
return send_and_receive(&tx_buffer[0], WRITE_RSP_SIZE, &rx_buffer[0],
|
||||
WRITE_DELAY, WRITE_EXEC_MAX - WRITE_DELAY);
|
||||
}
|
67
avr/SHA204/SHA204.h
Normal file
67
avr/SHA204/SHA204.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright 2013 Nusku Networks
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SHA204_Library_h
|
||||
#define SHA204_Library_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class SHA204 {
|
||||
private:
|
||||
virtual uint16_t SHA204_RESPONSE_TIMEOUT() = 0;
|
||||
void calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc);
|
||||
uint8_t check_crc(uint8_t *response);
|
||||
virtual uint8_t receive_bytes(uint8_t count, uint8_t *buffer) = 0;
|
||||
virtual uint8_t send_bytes(uint8_t count, uint8_t *buffer) = 0;
|
||||
virtual uint8_t send_byte(uint8_t value) = 0;
|
||||
virtual uint8_t receive_response(uint8_t size, uint8_t *response) = 0;
|
||||
virtual uint8_t send_command(uint8_t count, uint8_t * command) = 0;
|
||||
virtual uint8_t chip_wakeup() = 0; // Called this because wakeup() was causing method lookup issues with wakeup(*response)
|
||||
|
||||
|
||||
public:
|
||||
virtual uint8_t sleep() = 0;
|
||||
virtual uint8_t idle() = 0;
|
||||
uint8_t wakeup(uint8_t *response);
|
||||
|
||||
uint8_t execute(uint8_t op_code, uint8_t param1, uint16_t param2,
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
|
||||
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
|
||||
uint8_t check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2,
|
||||
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
|
||||
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
|
||||
|
||||
uint8_t send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout);
|
||||
virtual uint8_t resync(uint8_t size, uint8_t *response) = 0;
|
||||
|
||||
uint8_t serialNumber(uint8_t *response);
|
||||
|
||||
uint8_t check_mac(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint8_t key_id, uint8_t *client_challenge, uint8_t *client_response, uint8_t *other_data);
|
||||
uint8_t derive_key(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t random, uint8_t target_key, uint8_t *mac);
|
||||
uint8_t dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer);
|
||||
uint8_t gen_dig(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint8_t key_id, uint8_t *other_data);
|
||||
uint8_t hmac(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint16_t key_id);
|
||||
uint8_t lock(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t summary);
|
||||
uint8_t mac(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint16_t key_id, uint8_t *challenge);
|
||||
uint8_t nonce(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint8_t *numin);
|
||||
uint8_t pause(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t selector);
|
||||
uint8_t random(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode);
|
||||
uint8_t read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address);
|
||||
uint8_t update_extra(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t mode, uint8_t new_value);
|
||||
uint8_t write(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address, uint8_t *value, uint8_t *mac);
|
||||
};
|
||||
|
||||
#endif
|
273
avr/SHA204/SHA204Definitions.h
Normal file
273
avr/SHA204/SHA204Definitions.h
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
Copyright 2013 Nusku Networks
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SHA204_Library_Definitions_h
|
||||
#define SHA204_Library_Definitions_h
|
||||
|
||||
/* sha204_physical.h */
|
||||
|
||||
#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response
|
||||
#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet
|
||||
#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response
|
||||
#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response
|
||||
//#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units
|
||||
//#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms
|
||||
#define SHA204_WAKEUP_PULSE_WIDTH 62 // us (Twlo)
|
||||
#define SHA204_WAKEUP_DELAY 2.5 // ms (Twhi)
|
||||
|
||||
/* sha204_comm_marshaling.h */
|
||||
// command op-code definitions
|
||||
#define SHA204_CHECKMAC ((uint8_t) 0x28) //!< CheckMac command op-code
|
||||
#define SHA204_DERIVE_KEY ((uint8_t) 0x1C) //!< DeriveKey command op-code
|
||||
#define SHA204_DEVREV ((uint8_t) 0x30) //!< DevRev command op-code
|
||||
#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code
|
||||
#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code
|
||||
#define SHA204_LOCK ((uint8_t) 0x17) //!< Lock command op-code
|
||||
#define SHA204_MAC ((uint8_t) 0x08) //!< MAC command op-code
|
||||
#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code
|
||||
#define SHA204_PAUSE ((uint8_t) 0x01) //!< Pause command op-code
|
||||
#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code
|
||||
#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code
|
||||
#define SHA204_UPDATE_EXTRA ((uint8_t) 0x20) //!< UpdateExtra command op-code
|
||||
#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code
|
||||
|
||||
// packet size definitions
|
||||
#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data
|
||||
|
||||
// parameter range definitions
|
||||
#define SHA204_KEY_ID_MAX ((uint8_t) 15) //!< maximum value for key id
|
||||
#define SHA204_OTP_BLOCK_MAX ((uint8_t) 1) //!< maximum value for OTP block
|
||||
|
||||
// definitions for command packet indexes common to all commands
|
||||
#define SHA204_COUNT_IDX ( 0) //!< command packet index for count
|
||||
#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code
|
||||
#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter
|
||||
#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter
|
||||
#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter
|
||||
|
||||
// zone definitions
|
||||
#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone
|
||||
#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone
|
||||
#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone
|
||||
#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask
|
||||
#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes.
|
||||
#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes.
|
||||
#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes.
|
||||
#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone.
|
||||
#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone.
|
||||
#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0.
|
||||
|
||||
// CheckMAC command definitions
|
||||
#define CHECKMAC_MODE_IDX SHA204_PARAM1_IDX //!< CheckMAC command index for mode
|
||||
#define CHECKMAC_KEYID_IDX SHA204_PARAM2_IDX //!< CheckMAC command index for key identifier
|
||||
#define CHECKMAC_CLIENT_CHALLENGE_IDX SHA204_DATA_IDX //!< CheckMAC command index for client challenge
|
||||
#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response
|
||||
#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data
|
||||
#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size
|
||||
#define CHECKMAC_MODE_MASK ((uint8_t) 0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0.
|
||||
#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge
|
||||
#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response
|
||||
#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data"
|
||||
|
||||
// DeriveKey command definitions
|
||||
#define DERIVE_KEY_RANDOM_IDX SHA204_PARAM1_IDX //!< DeriveKey command index for random bit
|
||||
#define DERIVE_KEY_TARGETKEY_IDX SHA204_PARAM2_IDX //!< DeriveKey command index for target slot
|
||||
#define DERIVE_KEY_MAC_IDX SHA204_DATA_IDX //!< DeriveKey command index for optional MAC
|
||||
#define DERIVE_KEY_COUNT_SMALL SHA204_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC
|
||||
#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC
|
||||
#define DERIVE_KEY_RANDOM_FLAG ((uint8_t) 4) //!< DeriveKey 1. parameter
|
||||
#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size
|
||||
|
||||
// DevRev command definitions
|
||||
#define DEVREV_PARAM1_IDX SHA204_PARAM1_IDX //!< DevRev command index for 1. parameter (ignored)
|
||||
#define DEVREV_PARAM2_IDX SHA204_PARAM2_IDX //!< DevRev command index for 2. parameter (ignored)
|
||||
#define DEVREV_COUNT SHA204_CMD_SIZE_MIN //!< DevRev command packet size
|
||||
|
||||
// GenDig command definitions
|
||||
#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone
|
||||
#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id
|
||||
#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data
|
||||
#define GENDIG_COUNT SHA204_CMD_SIZE_MIN //!< GenDig command packet size without "other data"
|
||||
#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data"
|
||||
#define GENDIG_OTHER_DATA_SIZE (4) //!< GenDig size of "other data"
|
||||
#define GENDIG_ZONE_CONFIG ((uint8_t) 0) //!< GenDig zone id config
|
||||
#define GENDIG_ZONE_OTP ((uint8_t) 1) //!< GenDig zone id OTP
|
||||
#define GENDIG_ZONE_DATA ((uint8_t) 2) //!< GenDig zone id data
|
||||
|
||||
// HMAC command definitions
|
||||
#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode
|
||||
#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id
|
||||
#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size
|
||||
#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0.
|
||||
|
||||
// Lock command definitions
|
||||
#define LOCK_ZONE_IDX SHA204_PARAM1_IDX //!< Lock command index for zone
|
||||
#define LOCK_SUMMARY_IDX SHA204_PARAM2_IDX //!< Lock command index for summary
|
||||
#define LOCK_COUNT SHA204_CMD_SIZE_MIN //!< Lock command packet size
|
||||
#define LOCK_ZONE_NO_CONFIG ((uint8_t) 0x01) //!< Lock zone is OTP or Data
|
||||
#define LOCK_ZONE_NO_CRC ((uint8_t) 0x80) //!< Lock command: Ignore summary.
|
||||
#define LOCK_ZONE_MASK (0x81) //!< Lock parameter 1 bits 2 to 6 are 0.
|
||||
|
||||
// Mac command definitions
|
||||
#define MAC_MODE_IDX SHA204_PARAM1_IDX //!< MAC command index for mode
|
||||
#define MAC_KEYID_IDX SHA204_PARAM2_IDX //!< MAC command index for key id
|
||||
#define MAC_CHALLENGE_IDX SHA204_DATA_IDX //!< MAC command index for optional challenge
|
||||
#define MAC_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< MAC command packet size without challenge
|
||||
#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge
|
||||
#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t) 0x01) //!< MAC mode bit 0: second SHA block from TempKey
|
||||
#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t) 0x02) //!< MAC mode bit 1: first SHA block from TempKey
|
||||
#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t) 0x04) //!< MAC mode bit 2: match TempKey.SourceFlag
|
||||
#define MAC_MODE_PASSTHROUGH ((uint8_t) 0x07) //!< MAC mode bit 0-2: pass-through mode
|
||||
#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t) 0x10) //!< MAC mode bit 4: include first 88 OTP bits
|
||||
#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t) 0x20) //!< MAC mode bit 5: include first 64 OTP bits
|
||||
#define MAC_MODE_INCLUDE_SN ((uint8_t) 0x40) //!< MAC mode bit 6: include serial number
|
||||
#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge
|
||||
#define MAC_MODE_MASK ((uint8_t) 0x77) //!< MAC mode bits 3 and 7 are 0.
|
||||
|
||||
// Nonce command definitions
|
||||
#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode
|
||||
#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter
|
||||
#define NONCE_INPUT_IDX SHA204_DATA_IDX //!< Nonce command index for input data
|
||||
#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data
|
||||
#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data
|
||||
#define NONCE_MODE_MASK ((uint8_t) 3) //!< Nonce mode bits 2 to 7 are 0.
|
||||
#define NONCE_MODE_SEED_UPDATE ((uint8_t) 0x00) //!< Nonce mode: update seed
|
||||
#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Nonce mode: do not update seed
|
||||
#define NONCE_MODE_INVALID ((uint8_t) 0x02) //!< Nonce mode 2 is invalid.
|
||||
#define NONCE_MODE_PASSTHROUGH ((uint8_t) 0x03) //!< Nonce mode: pass-through
|
||||
#define NONCE_NUMIN_SIZE (20) //!< Nonce data length
|
||||
#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3)
|
||||
|
||||
// Pause command definitions
|
||||
#define PAUSE_SELECT_IDX SHA204_PARAM1_IDX //!< Pause command index for Selector
|
||||
#define PAUSE_PARAM2_IDX SHA204_PARAM2_IDX //!< Pause command index for 2. parameter
|
||||
#define PAUSE_COUNT SHA204_CMD_SIZE_MIN //!< Pause command packet size
|
||||
|
||||
// Random command definitions
|
||||
#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode
|
||||
#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter
|
||||
#define RANDOM_COUNT SHA204_CMD_SIZE_MIN //!< Random command packet size
|
||||
#define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update
|
||||
#define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update
|
||||
|
||||
// Read command definitions
|
||||
#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone
|
||||
#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address
|
||||
#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size
|
||||
#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0.
|
||||
#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes
|
||||
|
||||
// UpdateExtra command definitions
|
||||
#define UPDATE_MODE_IDX SHA204_PARAM1_IDX //!< UpdateExtra command index for mode
|
||||
#define UPDATE_VALUE_IDX SHA204_PARAM2_IDX //!< UpdateExtra command index for new value
|
||||
#define UPDATE_COUNT SHA204_CMD_SIZE_MIN //!< UpdateExtra command packet size
|
||||
#define UPDATE_CONFIG_BYTE_86 ((uint8_t) 0x01) //!< UpdateExtra mode: update Config byte 86
|
||||
|
||||
// Write command definitions
|
||||
#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone
|
||||
#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address
|
||||
#define WRITE_VALUE_IDX SHA204_DATA_IDX //!< Write command index for data
|
||||
#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data
|
||||
#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data
|
||||
#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC
|
||||
#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC
|
||||
#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC
|
||||
#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC
|
||||
#define WRITE_MAC_SIZE (32) //!< Write MAC size
|
||||
#define WRITE_ZONE_MASK ((uint8_t) 0xC3) //!< Write zone bits 2 to 5 are 0.
|
||||
#define WRITE_ZONE_WITH_MAC ((uint8_t) 0x40) //!< Write zone bit 6: write encrypted with MAC
|
||||
|
||||
// Response size definitions
|
||||
#define CHECKMAC_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command
|
||||
#define DERIVE_KEY_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command
|
||||
#define DEVREV_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of DevRev command returns 4 bytes
|
||||
#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command
|
||||
#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command
|
||||
#define LOCK_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Lock command
|
||||
#define MAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of MAC command
|
||||
#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3
|
||||
#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command
|
||||
#define PAUSE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Pause command
|
||||
#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command
|
||||
#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes
|
||||
#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes
|
||||
#define TEMP_SENSE_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of TempSense command returns 4 bytes
|
||||
#define UPDATE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of UpdateExtra command
|
||||
#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command
|
||||
|
||||
// command timing definitions for minimum execution times (ms)
|
||||
#define CHECKMAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define DERIVE_KEY_DELAY ((uint8_t) (14.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define DEVREV_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define LOCK_DELAY ((uint8_t) ( 5.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define MAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define PAUSE_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define TEMP_SENSE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define UPDATE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
|
||||
|
||||
// command timing definitions for maximum execution times (ms)
|
||||
#define CHECKMAC_EXEC_MAX ((uint8_t) (38.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define DERIVE_KEY_EXEC_MAX ((uint8_t) (62.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define DEVREV_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define LOCK_EXEC_MAX ((uint8_t) (24.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define MAC_EXEC_MAX ((uint8_t) (35.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define PAUSE_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define TEMP_SENSE_EXEC_MAX ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define UPDATE_EXEC_MAX ((uint8_t) ( 6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
|
||||
|
||||
/* from sha204_comm.h */
|
||||
|
||||
#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay
|
||||
#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte)
|
||||
#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac)
|
||||
#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes
|
||||
#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response
|
||||
#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response
|
||||
#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error
|
||||
#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error
|
||||
#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error
|
||||
#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error
|
||||
|
||||
/* EEPROM Addresses */
|
||||
/* Configuration Zone */
|
||||
#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone
|
||||
#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum
|
||||
#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone
|
||||
#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE
|
||||
#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status
|
||||
#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204
|
||||
#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode
|
||||
#define ADDRESS_SELECTOR 19 // Controls writability of Selector
|
||||
|
||||
/* from sha204_config.h */
|
||||
|
||||
#define CPU_CLOCK_DEVIATION_POSITIVE (1.01)
|
||||
#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99)
|
||||
#define SHA204_RETRY_COUNT (1)
|
||||
|
||||
#endif
|
48
avr/SHA204/SHA204ReturnCodes.h
Normal file
48
avr/SHA204/SHA204ReturnCodes.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// ATMEL Microcontroller Software Support - Colorado Springs, CO -
|
||||
// ----------------------------------------------------------------------------
|
||||
// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** \file
|
||||
* \brief SHA204 Library Return Code Definitions
|
||||
* \author Atmel Crypto Products
|
||||
* \date September 27, 2010
|
||||
*/
|
||||
|
||||
#ifndef SHA204_LIB_RETURN_CODES_H
|
||||
# define SHA204_LIB_RETURN_CODES_H
|
||||
|
||||
#include <stddef.h> // data type definitions
|
||||
|
||||
/** \todo Use same values for same meanings for SHA204 and AES132.
|
||||
* */
|
||||
|
||||
#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded.
|
||||
#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error
|
||||
#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error
|
||||
#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error
|
||||
#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown
|
||||
#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state.
|
||||
#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error
|
||||
#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.)
|
||||
#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set
|
||||
#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size.
|
||||
#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received
|
||||
#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0.
|
||||
#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response.
|
||||
#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up
|
||||
|
||||
#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules.
|
||||
#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0.
|
||||
|
||||
#endif
|
256
avr/SHA204/SHA204SWI.cpp
Normal file
256
avr/SHA204/SHA204SWI.cpp
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* SHA204SWI.c
|
||||
* (c) 2014 flabbergast
|
||||
* Communicate with ATSHA204 using Single-Wire Interface:
|
||||
* Main file: extends the generic SHA204 class and implements the hardware protocol.
|
||||
*
|
||||
* Most of the code is from https://github.com/bettse/arduino_projects/tree/master/libraries/SHA204
|
||||
* (license below?)
|
||||
*
|
||||
* Modifications by flabbergast to run on XMEGA hardware + some "simplifications" in timing.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2013 Nusku Networks
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "SHA204.h"
|
||||
#include "SHA204ReturnCodes.h"
|
||||
#include "SHA204Definitions.h"
|
||||
#include "SHA204SWI.h"
|
||||
#include <util/delay.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
uint16_t SHA204SWI::SHA204_RESPONSE_TIMEOUT() {
|
||||
return SHA204_RESPONSE_TIMEOUT_VALUE;
|
||||
}
|
||||
|
||||
// atsha204Class Constructor
|
||||
// nothing to do (pin settings via defines)
|
||||
SHA204SWI::SHA204SWI() {
|
||||
}
|
||||
|
||||
// power up (powered from appropriate pin)
|
||||
void SHA204SWI::power_up(void) {
|
||||
S_POWER_UP;
|
||||
}
|
||||
|
||||
/* SWI bit bang functions */
|
||||
|
||||
uint8_t SHA204SWI::chip_wakeup() {
|
||||
S_PIN_DIR_OUT;
|
||||
S_PIN_LOW;
|
||||
_delay_us(SHA204_WAKEUP_PULSE_WIDTH);
|
||||
S_PIN_HIGH;
|
||||
_delay_ms(SHA204_WAKEUP_DELAY);
|
||||
|
||||
return SHA204_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::sleep() {
|
||||
return send_byte(SHA204_SWI_FLAG_SLEEP);
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::idle() {
|
||||
return send_byte(SHA204_SWI_FLAG_IDLE);
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::resync(uint8_t size, uint8_t *response) {
|
||||
// Try to re-synchronize without sending a Wake token
|
||||
// (step 1 of the re-synchronization process).
|
||||
_delay_ms(SHA204_SYNC_TIMEOUT);
|
||||
uint8_t ret_code = receive_response(size, response);
|
||||
if (ret_code == SHA204_SUCCESS)
|
||||
return ret_code;
|
||||
|
||||
// We lost communication. Send a Wake pulse and try
|
||||
// to receive a response (steps 2 and 3 of the
|
||||
// re-synchronization process).
|
||||
(void) sleep();
|
||||
ret_code = wakeup(response);
|
||||
|
||||
// Translate a return value of success into one
|
||||
// that indicates that the device had to be woken up
|
||||
// and might have lost its TempKey.
|
||||
return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code);
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::send_bytes(uint8_t count, uint8_t *buffer) {
|
||||
uint8_t i, bit_mask;
|
||||
|
||||
// Disable interrupts while sending.
|
||||
cli();
|
||||
|
||||
S_PIN_DIR_OUT;
|
||||
|
||||
// Wait turn around time.
|
||||
_delay_us(RX_TX_DELAY);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) {
|
||||
if (bit_mask & buffer[i]) {
|
||||
S_PIN_LOW;
|
||||
_delay_us(BIT_DELAY); //BIT_DELAY_1;
|
||||
S_PIN_HIGH;
|
||||
_delay_us(7*BIT_DELAY); //BIT_DELAY_7;
|
||||
} else {
|
||||
// Send a zero bit.
|
||||
S_PIN_LOW;
|
||||
_delay_us(BIT_DELAY); //BIT_DELAY_1;
|
||||
S_PIN_HIGH;
|
||||
_delay_us(BIT_DELAY); //BIT_DELAY_1;
|
||||
S_PIN_LOW;
|
||||
_delay_us(BIT_DELAY); //BIT_DELAY_1;
|
||||
S_PIN_HIGH;
|
||||
_delay_us(5*BIT_DELAY); //BIT_DELAY_5;
|
||||
}
|
||||
_delay_us(2); // since 8*BIT_DELAY < 37 us (datasheet / Table 7-3)
|
||||
}
|
||||
}
|
||||
sei(); // enable_interrupts();
|
||||
return SWI_FUNCTION_RETCODE_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::send_byte(uint8_t value) {
|
||||
return send_bytes(1, &value);
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::receive_bytes(uint8_t count, uint8_t *buffer) {
|
||||
uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS;
|
||||
uint8_t i;
|
||||
uint8_t bit_mask;
|
||||
uint8_t pulse_count;
|
||||
uint16_t timeout_count;
|
||||
|
||||
// Disable interrupts while receiving.
|
||||
cli();
|
||||
|
||||
// Configure signal pin as input.
|
||||
S_PIN_DIR_IN;
|
||||
|
||||
// Receive bits and store in buffer.
|
||||
for (i = 0; i < count; i++) {
|
||||
for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) {
|
||||
pulse_count = 0;
|
||||
|
||||
// Make sure that the variable below is big enough.
|
||||
// Change it to uint16_t if 255 is too small, but be aware that
|
||||
// the loop resolution decreases on an 8-bit controller in that case.
|
||||
timeout_count = START_PULSE_TIME_OUT;
|
||||
|
||||
// Detect start bit.
|
||||
while (--timeout_count > 0) {
|
||||
// Wait for falling edge.
|
||||
if ((S_PIN_IS_HIGH) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout_count == 0) {
|
||||
status = SWI_FUNCTION_RETCODE_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
// Wait for rising edge.
|
||||
if (S_PIN_IS_HIGH) {
|
||||
// For an Atmel microcontroller this might be faster than "pulse_count++".
|
||||
pulse_count = 1;
|
||||
break;
|
||||
}
|
||||
} while (--timeout_count > 0);
|
||||
|
||||
if (pulse_count == 0) {
|
||||
status = SWI_FUNCTION_RETCODE_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Trying to measure the time of start bit and calculating the timeout
|
||||
// for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU.
|
||||
// (NB by flabbergast: running now on 32MHz XMEGA. so maybe...)
|
||||
// So let's just wait the maximum time for the falling edge of a zero bit
|
||||
// to arrive after we have detected the rising edge of the start bit.
|
||||
timeout_count = ZERO_PULSE_TIME_OUT;
|
||||
|
||||
// Detect possible edge indicating zero bit.
|
||||
do {
|
||||
if ((S_PIN_IS_HIGH) == 0) {
|
||||
// For an Atmel microcontroller this might be faster than "pulse_count++".
|
||||
pulse_count = 2;
|
||||
break;
|
||||
}
|
||||
} while (--timeout_count > 0);
|
||||
|
||||
// Wait for rising edge of zero pulse before returning. Otherwise we might interpret
|
||||
// its rising edge as the next start pulse.
|
||||
if (pulse_count == 2) {
|
||||
do {
|
||||
if (S_PIN_IS_HIGH)
|
||||
break;
|
||||
} while (timeout_count-- > 0);
|
||||
}
|
||||
|
||||
// Update byte at current buffer index.
|
||||
else
|
||||
buffer[i] |= bit_mask; // received "one" bit
|
||||
}
|
||||
|
||||
if (status != SWI_FUNCTION_RETCODE_SUCCESS)
|
||||
break;
|
||||
}
|
||||
sei(); // enable_interrupts();
|
||||
|
||||
if (status == SWI_FUNCTION_RETCODE_TIMEOUT) {
|
||||
if (i > 0)
|
||||
// Indicate that we timed out after having received at least one byte.
|
||||
status = SWI_FUNCTION_RETCODE_RX_FAIL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::receive_response(uint8_t size, uint8_t *response) {
|
||||
uint8_t count_byte;
|
||||
uint8_t i;
|
||||
uint8_t ret_code;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
response[i] = 0;
|
||||
|
||||
(void) send_byte(SHA204_SWI_FLAG_TX);
|
||||
|
||||
ret_code = receive_bytes(size, response);
|
||||
if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) {
|
||||
count_byte = response[SHA204_BUFFER_POS_COUNT];
|
||||
if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size))
|
||||
return SHA204_INVALID_SIZE;
|
||||
|
||||
return SHA204_SUCCESS;
|
||||
}
|
||||
|
||||
// Translate error so that the Communication layer
|
||||
// can distinguish between a real error or the
|
||||
// device being busy executing a command.
|
||||
if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT)
|
||||
return SHA204_RX_NO_RESPONSE;
|
||||
else
|
||||
return SHA204_RX_FAIL;
|
||||
}
|
||||
|
||||
uint8_t SHA204SWI::send_command(uint8_t count, uint8_t * command) {
|
||||
uint8_t ret_code = send_byte(SHA204_SWI_FLAG_CMD);
|
||||
if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS)
|
||||
return SHA204_COMM_FAIL;
|
||||
|
||||
return send_bytes(count, command);
|
||||
}
|
92
avr/SHA204/SHA204SWI.h
Normal file
92
avr/SHA204/SHA204SWI.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* SHA204SWI.h
|
||||
* (c) 2014 flabbergast
|
||||
* Communicate with ATSHA204 using Single-Wire Interface:
|
||||
* Main header file.
|
||||
*
|
||||
* Most of the code is from https://github.com/bettse/arduino_projects/tree/master/libraries/SHA204
|
||||
* (license below?)
|
||||
*
|
||||
* Modifications by flabbergast to run on XMEGA hardware + some "simplifications" in timing.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright 2013 Nusku Networks
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SHA204_Library_SWI_h
|
||||
#define SHA204_Library_SWI_h
|
||||
|
||||
#include "SHA204.h"
|
||||
#include "SHA204SWI_hardware_config.h"
|
||||
|
||||
/* bitbang_config.h */
|
||||
|
||||
//#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns)
|
||||
//#define START_PULSE_WIDTH (4340) //! width of start pulse (ns)
|
||||
//#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns)
|
||||
//#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit
|
||||
#if (F_CPU == 32000000)
|
||||
#define START_PULSE_TIME_OUT (510) //! This value is decremented while waiting for the falling edge of a start pulse.
|
||||
#define ZERO_PULSE_TIME_OUT (52) //! This value is decremented while waiting for the falling edge of a zero pulse.
|
||||
#elif (F_CPU == 16000000)
|
||||
#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse.
|
||||
#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse.
|
||||
#else
|
||||
#error "You need to define some constants for your F_CPU speed!"
|
||||
#endif
|
||||
|
||||
// my defs
|
||||
#define BIT_DELAY 4 // us (zero/one transmission pulse length)
|
||||
#define RX_TX_DELAY 93 // us (turnaround time from receive to transmit)
|
||||
|
||||
/* swi_phys.h */
|
||||
|
||||
#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded.
|
||||
#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out.
|
||||
#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received.
|
||||
|
||||
/* sha204_swi.c */
|
||||
#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command
|
||||
#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response
|
||||
#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode
|
||||
#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode
|
||||
|
||||
/* from sha204_config.h */
|
||||
#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts
|
||||
#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits).
|
||||
#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine
|
||||
|
||||
class SHA204SWI : public SHA204 {
|
||||
private:
|
||||
const static uint16_t SHA204_RESPONSE_TIMEOUT_VALUE = ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE); //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag.
|
||||
|
||||
uint16_t SHA204_RESPONSE_TIMEOUT();
|
||||
uint8_t receive_bytes(uint8_t count, uint8_t *buffer);
|
||||
uint8_t send_bytes(uint8_t count, uint8_t *buffer);
|
||||
uint8_t send_byte(uint8_t value);
|
||||
uint8_t chip_wakeup();
|
||||
uint8_t receive_response(uint8_t size, uint8_t *response);
|
||||
uint8_t send_command(uint8_t count, uint8_t * command);
|
||||
|
||||
public:
|
||||
SHA204SWI(void);
|
||||
void power_up();
|
||||
uint8_t sleep();
|
||||
uint8_t idle();
|
||||
uint8_t resync(uint8_t size, uint8_t *response);
|
||||
};
|
||||
|
||||
#endif
|
74
avr/SHA204/SHA204SWI_hardware_config.h
Normal file
74
avr/SHA204/SHA204SWI_hardware_config.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* SHA204SWI_hardware_config.h
|
||||
* (c) 2014 flabbergast
|
||||
* Define macros to be used for Single Wire bit-bang communication *
|
||||
*
|
||||
* EDIT THIS FILE TO MATCH YOUR HARDWARE CONFIG!
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHA204SWI_hardware_config_h
|
||||
#define SHA204SWI_hardware_config_h
|
||||
|
||||
// Note: pull-up on the signal pin is assumed to exist (ie internal pullup is not used)
|
||||
|
||||
/*************************\
|
||||
**** FOR XMEGA CHIPS ****
|
||||
\*************************/
|
||||
#if (defined(__AVR_ATxmega128A3U__))
|
||||
// Modify below!
|
||||
// -> If you use actual GND and VCC pins for power, ignore the _VCC_ and _GND_ settings
|
||||
// and redefine the S_POWER_UP macro to be blank
|
||||
#define SHA204_PORT PORTB
|
||||
#define SHA204_BIT (1 << 2)
|
||||
#define SHA204_GND_PORT PORTB
|
||||
#define SHA204_GND_BIT (1 << 3)
|
||||
#define SHA204_VCC_PORT PORTB
|
||||
#define SHA204_VCC_BIT (1 << 1)
|
||||
|
||||
// Choose the appropriate S_POWER_UP macro according to your power setup
|
||||
// #define S_POWER_UP {} // use this if using actual GND and VCC supply
|
||||
#define S_POWER_UP SHA204_GND_PORT.DIRSET = SHA204_GND_BIT; SHA204_GND_PORT.OUTCLR = SHA204_GND_BIT; SHA204_VCC_PORT.DIRSET = SHA204_VCC_BIT; SHA204_VCC_PORT.OUTSET = SHA204_VCC_BIT // use this if powering from PORT pins
|
||||
|
||||
// Leave the following code alone
|
||||
#define S_PIN_DIR_OUT SHA204_PORT.DIRSET = SHA204_BIT
|
||||
#define S_PIN_DIR_IN SHA204_PORT.DIRCLR = SHA204_BIT
|
||||
#define S_PIN_HIGH SHA204_PORT.OUTSET = SHA204_BIT
|
||||
#define S_PIN_LOW SHA204_PORT.OUTCLR = SHA204_BIT
|
||||
#define S_PIN_IS_HIGH SHA204_PORT.IN & SHA204_BIT
|
||||
|
||||
/********************************\
|
||||
**** FOR AVR8/Arduino CHIPS ****
|
||||
\********************************/
|
||||
#else
|
||||
// Modify below!
|
||||
// -> If you use actual GND and VCC pins for power, ignore the _VCC_ and _GND_ settings
|
||||
// and redefine the S_POWER_UP macro to be blank
|
||||
// -> Have a look at http://arduino.cc/en/Hacking/PinMapping168 to find out
|
||||
// the correct port/bit from an Arduino pin number (just need to change the
|
||||
// last letters and the bit, e.g. Arduino's digital pin 7 is "PD7", so one
|
||||
// would use PORTD, PIND, DDRD and the _BIT would be set to (1<<7).
|
||||
#define SHA204_PORT PORTB
|
||||
#define SHA204_PIN PINB
|
||||
#define SHA204_DDR DDRB
|
||||
#define SHA204_BIT (1<<1)
|
||||
#define SHA204_GND_PORT PORTB
|
||||
#define SHA204_GND_DDR DDRB
|
||||
#define SHA204_GND_BIT (1 << 0)
|
||||
#define SHA204_VCC_PORT PORTB
|
||||
#define SHA204_VCC_DDR DDRB
|
||||
#define SHA204_VCC_BIT (1 << 2)
|
||||
|
||||
// Choose the appropriate S_POWER_UP macro according to your power setup
|
||||
#define S_POWER_UP {} // use this if using actual GND and VCC supply
|
||||
// #define S_POWER_UP SHA204_GND_DDR|=SHA204_GND_BIT; SHA204_GND_PORT&=~SHA204_GND_BIT; SHA204_VCC_DDR|=SHA204_VCC_BIT; SHA204_VCC_PORT|=SHA204_VCC_BIT; // use this if powering from PORT pins
|
||||
|
||||
// Leave the following code alone
|
||||
#define S_PIN_DIR_OUT SHA204_DDR |= SHA204_BIT
|
||||
#define S_PIN_DIR_IN SHA204_DDR &= ~SHA204_BIT
|
||||
#define S_PIN_HIGH SHA204_PORT |= SHA204_BIT
|
||||
#define S_PIN_LOW SHA204_PORT &= ~SHA204_BIT
|
||||
#define S_PIN_IS_HIGH SHA204_PIN & SHA204_BIT
|
||||
#endif
|
||||
|
||||
#endif
|
84
avr/Timer.c
Normal file
84
avr/Timer.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Timer.c
|
||||
* (c) 2014 flabbergast
|
||||
* implements Arduino-like millis() function via RTC timer interrupt (on XMEGAs)
|
||||
* Note: the XMEGA version counts in 10/1024 secs, so not exactly tens of milliseconds (2.4% error :)
|
||||
* Note: the AVR8 version counts in 10.24 millisecs (wrong the other way than XMEGA :)
|
||||
*
|
||||
* Credits:
|
||||
* - XMEGA code from: http://www.jtronics.de/avr-projekte/xmega-tutorial/xmega-tutorial-real-time-counter.html
|
||||
*/
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
volatile uint32_t current_time;
|
||||
|
||||
#if (defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__)) // use TIMER0 compare interrupt to keep track of time
|
||||
volatile uint8_t helper_counter;
|
||||
void Timer_Init(void) {
|
||||
TCCR0B |= (1 << CS00)|(1 << CS01); // prescaler F_CPU/64
|
||||
TCNT0 = 0; // initalize the counter
|
||||
helper_counter = 0;
|
||||
TIMSK0 |= (1 << TOIE0); // enable TIMER0 overflow interrupt (fires every 256 prescaled cycles)
|
||||
// altogether the int fires every 1.024 ms on F_CPU=16MHz and 2.048 ms on F_CPU=8MHz
|
||||
}
|
||||
|
||||
#if (F_CPU == 16000000)
|
||||
#define TIMER_HELPER_CONSTANT 10
|
||||
#elif (F_CPU == 8000000)
|
||||
#define TIMER_HELPER_CONSTANT 5
|
||||
#else
|
||||
#error "Unusual F_CPU: you should define some constants in Timer.c."
|
||||
#endif
|
||||
// TIMER0 overflow interrupt handler
|
||||
ISR(TIMER0_OVF_vect) {
|
||||
helper_counter++;
|
||||
if(helper_counter>=TIMER_HELPER_CONSTANT) {
|
||||
current_time++;
|
||||
helper_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#elif (defined(__AVR_ATxmega128A3U__)) // use internal RTC oscillator to generate interrupts
|
||||
void Timer_Init(void) {
|
||||
current_time = 0;
|
||||
//############################### Clock für RTC aktivieren
|
||||
// Unlock access to protected IO register for 4 cycles
|
||||
CCP = CCP_IOREG_gc;
|
||||
// Internen RTC 32768KHz Oszillator aktivieren
|
||||
OSC.CTRL |= OSC_RC32KEN_bm;
|
||||
// Internen Oszillator mit 1024khz für RTC verwenden
|
||||
CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc|CLK_RTCEN_bm;
|
||||
// Do not prescale (fire 1024 times / second)
|
||||
RTC.CTRL = RTC_PRESCALER_DIV1_gc;
|
||||
// Warten bis Takt und RTC synchronisiert ist
|
||||
while(RTC.STATUS & RTC_SYNCBUSY_bm);
|
||||
|
||||
//############################### RTC --> 1Hz
|
||||
//Timertopwert einstellen
|
||||
RTC.PER = 10; // fire an interrupt every 10 / 1024 sec
|
||||
//Timeroverflow Interrupt mit Interrupt Priorität Hoch einstellen
|
||||
RTC.INTCTRL |= RTC_OVFINTLVL_HI_gc;
|
||||
//Timerregister CNT auf 0 stellen
|
||||
RTC.CNT = 0;
|
||||
//RTC.COMP = 2; // note: if COMP>PER, no 'compare' interrupt will ever be generated
|
||||
}
|
||||
|
||||
//################################################## ISR RTC 1Hz
|
||||
ISR(RTC_OVF_vect) {
|
||||
current_time++;
|
||||
// testing: toggle LED on E0 approx every 1 sec
|
||||
//if(0 == (current_time % 102))
|
||||
// PORTE.OUTTGL = 1;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "You should define some timer in Timer.c for your ATMEL chip."
|
||||
#endif
|
||||
|
||||
uint32_t millis10(void) {
|
||||
return current_time;
|
||||
}
|
||||
|
13
avr/Timer.h
Normal file
13
avr/Timer.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Timer.h
|
||||
* (c) 2014 flabbergast
|
||||
* implements Arduino-like millis() function via RTC timer interrupt (on XMEGAs)
|
||||
*/
|
||||
|
||||
#ifndef _PROJECT_TIMER_H_
|
||||
#define _PROJECT_TIMER_H_
|
||||
|
||||
void Timer_Init(void);
|
||||
uint32_t millis10(void);
|
||||
|
||||
#endif
|
50
avr/makefile
Normal file
50
avr/makefile
Normal file
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# LUFA Library
|
||||
# Copyright (C) Dean Camera, 2014.
|
||||
#
|
||||
# dean [at] fourwalledcubicle [dot] com
|
||||
# www.lufa-lib.org
|
||||
#
|
||||
# --------------------------------------
|
||||
# LUFA Project Makefile.
|
||||
# --------------------------------------
|
||||
|
||||
# Run "make help" for target help.
|
||||
|
||||
## Boards
|
||||
# xmega avr stick
|
||||
#MCU = atxmega128a3u
|
||||
#ARCH = XMEGA
|
||||
#BOARD = USER
|
||||
#F_CPU = 32000000
|
||||
#F_USB = 48000000
|
||||
# atmega32u4 stick
|
||||
MCU = atmega32u4
|
||||
ARCH = AVR8
|
||||
BOARD = OLIMEX32U4
|
||||
F_CPU = 16000000
|
||||
F_USB = $(F_CPU)
|
||||
AVRDUDE_PROGRAMMER = avr109
|
||||
AVRDUDE_PORT = /dev/tty.usbmodemfd111
|
||||
|
||||
# Compile setting
|
||||
OPTIMIZATION = s
|
||||
TARGET = sha204_playground
|
||||
SRC = $(TARGET).cpp LufaLayer.c Descriptors.c Timer.c $(shell find "SHA204" -name "*.cpp") $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS)
|
||||
LUFA_PATH = LUFA
|
||||
CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/
|
||||
LD_FLAGS =
|
||||
|
||||
# Default target
|
||||
all:
|
||||
|
||||
# Include LUFA build script makefiles
|
||||
include $(LUFA_PATH)/Build/lufa_core.mk
|
||||
include $(LUFA_PATH)/Build/lufa_sources.mk
|
||||
include $(LUFA_PATH)/Build/lufa_build.mk
|
||||
include $(LUFA_PATH)/Build/lufa_cppcheck.mk
|
||||
include $(LUFA_PATH)/Build/lufa_doxygen.mk
|
||||
include $(LUFA_PATH)/Build/lufa_dfu.mk
|
||||
include $(LUFA_PATH)/Build/lufa_hid.mk
|
||||
include $(LUFA_PATH)/Build/lufa_avrdude.mk
|
||||
include $(LUFA_PATH)/Build/lufa_atprogram.mk
|
807
avr/sha204_playground.cpp
Normal file
807
avr/sha204_playground.cpp
Normal file
|
@ -0,0 +1,807 @@
|
|||
/*
|
||||
* sha204_playground.cpp
|
||||
* (c) 2014 flabbergast
|
||||
*
|
||||
* Firmware for USB capable ATMEL chips (tested on atmega32U4 and
|
||||
* atxmega128a3u) to communicate with ATSHA204 (single-wire
|
||||
* interface) interactively, over Serial.
|
||||
*/
|
||||
|
||||
#include "LufaLayer.h"
|
||||
|
||||
#include "SHA204/SHA204SWI.h"
|
||||
#include "SHA204/SHA204Definitions.h" // for constants and such
|
||||
#include "SHA204/SHA204ReturnCodes.h" // want messages for return codes
|
||||
|
||||
/*************************************************************************
|
||||
* ----------------------- Global variables -----------------------------*
|
||||
*************************************************************************/
|
||||
|
||||
// when this byte is received, switch to binary mode
|
||||
#define BINARY_MODE_CHAR 0xFD
|
||||
|
||||
#define MAX_BUFFER_SIZE 100
|
||||
volatile uint8_t hexprint_separator = ' ';
|
||||
volatile uint8_t idle = 0;
|
||||
|
||||
/*************************************************************************
|
||||
* ----------------------- Helper functions -----------------------------*
|
||||
*************************************************************************/
|
||||
void hexprint(uint8_t *p, uint16_t length);
|
||||
void hexprint_noln(uint8_t *p, uint16_t length);
|
||||
void hexprint_byte(uint8_t b);
|
||||
void hexprint_byte_sep(uint8_t b);
|
||||
|
||||
#define W(s) usb_serial_write_P(PSTR(s))
|
||||
#define Wl(s) usb_serial_writeln_P(PSTR(s))
|
||||
|
||||
uint8_t get_bytes_serial(uint8_t *output, uint16_t len);
|
||||
void print_help(void);
|
||||
void print_executing(void);
|
||||
void print_received_from_sha(uint8_t *rx_buffer);
|
||||
void print_execute_params(uint8_t opcode, uint8_t param1);
|
||||
void print_return_code(uint8_t code);
|
||||
|
||||
void process_config(uint8_t *config);
|
||||
void sleep_or_idle(SHA204SWI *sha204);
|
||||
uint8_t receive_serial_binary_transaction(uint8_t *buffer, uint8_t len);
|
||||
uint8_t binary_mode_transaction(uint8_t *data, uint8_t rxsize, uint8_t *rx_buffer, SHA204SWI *sha204);
|
||||
#define BINARY_TRANSACTION_OK 0
|
||||
#define BINARY_TRANSACTION_RECEIVE_ERROR 1
|
||||
#define BINARY_TRANSACTION_PARAM_ERROR 2
|
||||
#define BINARY_TRANSACTION_EXECUTE_ERROR 3
|
||||
|
||||
/** Main program entry point. This routine contains the overall program flow, including initial
|
||||
* setup of all components and the main program loop.
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/* Variables */
|
||||
bool button_press_registered = false;
|
||||
uint32_t button_press_length = 0;
|
||||
|
||||
bool dtr,prev_dtr = false;
|
||||
|
||||
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
|
||||
uint8_t tx_buffer[MAX_BUFFER_SIZE];
|
||||
uint8_t configuration_zone[88];
|
||||
uint8_t r;
|
||||
uint8_t param1;
|
||||
uint16_t param2;
|
||||
uint8_t data1[32];
|
||||
uint8_t data2[32];
|
||||
uint8_t data3[14];
|
||||
|
||||
SHA204SWI sha204;
|
||||
|
||||
sha204.power_up();
|
||||
|
||||
/* Initialisation */
|
||||
init();
|
||||
|
||||
/* Must throw away unused bytes from the host, or it will lock up while waiting for the device */
|
||||
usb_serial_flush_input();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// run the task which checks the state of the button
|
||||
service_button();
|
||||
// for how long was the button pressed?
|
||||
button_press_length = button_pressed_for();
|
||||
// if at least 70ms and we haven't acted on this press yet
|
||||
if( button_press_length >= 7 && !button_press_registered ) {
|
||||
// remember that we've acted on the current button press
|
||||
button_press_registered = true;
|
||||
// announce the button press over the serial
|
||||
Wl("Button pressed.");
|
||||
// maybe do something else...
|
||||
}
|
||||
// was the button released after being pressed?
|
||||
if( button_press_registered && button_press_length < 7 ) {
|
||||
button_press_registered = false;
|
||||
}
|
||||
|
||||
// check dtr
|
||||
dtr = usb_serial_dtr();
|
||||
if( dtr && !prev_dtr ) {
|
||||
_delay_ms(50);
|
||||
W("\n\r");
|
||||
print_help();
|
||||
}
|
||||
prev_dtr = dtr;
|
||||
|
||||
// main serial processing
|
||||
if(usb_serial_available() > 0) {
|
||||
char c = (char)usb_serial_getchar();
|
||||
if(c==BINARY_MODE_CHAR) { // handle binary mode for one transaction
|
||||
r = receive_serial_binary_transaction(tx_buffer, MAX_BUFFER_SIZE); // blocking
|
||||
if(r == BINARY_TRANSACTION_OK)
|
||||
r = binary_mode_transaction(tx_buffer, SHA204_RSP_SIZE_MAX, rx_buffer, &sha204); // blocking
|
||||
// transmit the response
|
||||
usb_serial_putchar(r);
|
||||
if(r == BINARY_TRANSACTION_OK)
|
||||
for(r=0; r<rx_buffer[0]; r++)
|
||||
usb_serial_putchar(rx_buffer[r]);
|
||||
} else {
|
||||
if(idle)
|
||||
Wl("--- I ---");
|
||||
else
|
||||
Wl("--- S ---");
|
||||
switch(c) { // yes, code like this sucks
|
||||
case 's': // serial number
|
||||
Wl("Request serial number.");
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.serialNumber(rx_buffer);
|
||||
print_executing();
|
||||
print_return_code(r);
|
||||
Wl("Should get: 01 23 xx xx xx xx xx xx EE");
|
||||
W("Received SN: ");
|
||||
hexprint(rx_buffer, 9);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
break;
|
||||
case 'o': // config zone
|
||||
Wl("Request and display config zone contents.");
|
||||
print_executing();
|
||||
memset(configuration_zone,0,32);
|
||||
if(!(r=sha204.wakeup(rx_buffer))) { // read first 2 32-byte blocks manually
|
||||
if(!(r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG|READ_ZONE_MODE_32_BYTES,0))) {
|
||||
memcpy(configuration_zone,rx_buffer+1,32);
|
||||
if(!(r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG|READ_ZONE_MODE_32_BYTES,32))) {
|
||||
memcpy(configuration_zone+32, rx_buffer+1, 32);
|
||||
uint8_t addr = 64; // have to read the rest of the zone in 4-byte blocks
|
||||
while(addr < 88) {
|
||||
if((r=sha204.read(tx_buffer,rx_buffer,SHA204_ZONE_CONFIG,addr)))
|
||||
break;
|
||||
memcpy(configuration_zone+addr, rx_buffer+1, 4);
|
||||
addr+=4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
if(!r)
|
||||
process_config(configuration_zone);
|
||||
break;
|
||||
case 'c': // check_mac
|
||||
Wl("Calculate and compare MAC (CheckMAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter client challenge (32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
Wl("Enter client response (32 bytes; default 0):");
|
||||
memset((void *)data2, 0, 32);
|
||||
get_bytes_serial(data2, 32);
|
||||
Wl("Enter other data (13 bytes; default 0):");
|
||||
memset((void *)data3, 0, 13);
|
||||
get_bytes_serial(data3, 13);
|
||||
print_execute_params(SHA204_CHECKMAC,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
W("data2 ");
|
||||
hexprint(data2, 32);
|
||||
W("data3 ");
|
||||
hexprint(data3, 13);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.check_mac(tx_buffer, rx_buffer, param1, param2, data1, data2, data3);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'd': // derive_key
|
||||
Wl("Combine current key with nonce and store in a key slot (DeriveKey command).");
|
||||
Wl("Enter random (1 byte: 00 or 04; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Target Slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter MAC for validation (0 or 32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_DERIVE_KEY,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.derive_key(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'v': // dev_rev
|
||||
Wl("Request device revision.");
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.dev_rev(tx_buffer, rx_buffer);
|
||||
print_executing();
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
break;
|
||||
case 'g': // gen_dig
|
||||
Wl("Compute SHA-256 from TempKey+stored value, store result in TempKey (GenDig command).");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Key ID / OTP slot ID (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
Wl("Enter other data (4 bytes when CheckKey, otherwise ignored; default 0):");
|
||||
memset((void *)data1, 0, 4);
|
||||
get_bytes_serial(data1, 4);
|
||||
print_execute_params(SHA204_GENDIG,param1);
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 4);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.gen_dig(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'h': // HMAC
|
||||
Wl("Compute HMAC/SHA-256 digest from key + other info on device (HMAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_HMAC,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.hmac(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'm': // mac
|
||||
Wl("Compute SHA-256 from key + challenge + other info on device (MAC command).");
|
||||
Wl("Enter mode (1 byte; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Slot ID (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
Wl("Enter challenge (32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_MAC,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint(data1, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.mac(tx_buffer, rx_buffer, param1, param2, data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'n': // nonce
|
||||
Wl("Generate a nonce for subsequent use by other commands (Nonce command).");
|
||||
Wl("Enter mode (00 to 03; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter input value (20 or 32 bytes (dep on mode); default all 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
print_execute_params(SHA204_NONCE, param1);
|
||||
Wl("none");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.nonce(tx_buffer,rx_buffer,param1,data1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'r': // random
|
||||
Wl("Generate a random sequence.");
|
||||
Wl("Enter mode (00 or 01; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
print_execute_params(SHA204_RANDOM,param1);
|
||||
Wl("none");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.random(tx_buffer,rx_buffer,param1);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'e': // read
|
||||
Wl("Read from device.");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data, +0x80 to read 32 instead of 4 bytes; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Address (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_READ,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.read(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'w': // write
|
||||
Wl("Write to device.");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP or 02/Data,");
|
||||
Wl(" +0x80 to write 32 instead of 4 bytes, +0x40 to require encryption; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Address (2 bytes; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
Wl("Enter data (4 or 32 bytes; default 0):");
|
||||
memset((void *)data1, 0, 32);
|
||||
get_bytes_serial(data1, 32);
|
||||
Wl("Enter MAC to validate address and data (0 or 32 bytes; default 0):");
|
||||
memset((void *)data2, 0, 32);
|
||||
get_bytes_serial(data2, 32);
|
||||
print_execute_params(SHA204_WRITE,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte_sep((uint8_t)param2);
|
||||
W("data1 ");
|
||||
hexprint_noln(data1, 32);
|
||||
W("data2 ");
|
||||
hexprint(data2, 32);
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.write(tx_buffer, rx_buffer, param1, param2, data1, data2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'u': // update_extra
|
||||
Wl("Update 'UserExtra' bytes (84 and 85) in the Conf zone after locking.");
|
||||
Wl("Enter mode (1 byte: 00->update 84, 01->update 85; default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter new value (1 byte; default 0):");
|
||||
param2 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param2 = tx_buffer[0];
|
||||
print_execute_params(SHA204_UPDATE_EXTRA,param1);
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.update_extra(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'k': // wake
|
||||
Wl("Test waking up.");
|
||||
print_executing();
|
||||
r = sha204.wakeup(rx_buffer);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
Wl("Should receive: 04 11 33 43");
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case 'L': // lock
|
||||
Wl("Lock a zone. This is a one time thing! Once you lock a zone, it CAN'T BE UNLOCKED. EVER!");
|
||||
Wl("Enter zone (1 byte: 00/Config or 01/OTP_or_Data, +0x80 for 'force' (CRC ignored); default 0):");
|
||||
param1 = 0;
|
||||
if(1 == get_bytes_serial(tx_buffer, 1))
|
||||
param1 = tx_buffer[0];
|
||||
Wl("Enter Summary / CRC-16 of the zone (2 bytes, should be 0 if 'force'; default 0):");
|
||||
param2 = 0;
|
||||
if(2 == get_bytes_serial(tx_buffer, 2))
|
||||
param2 = tx_buffer[0]*256 + tx_buffer[1];
|
||||
print_execute_params(SHA204_LOCK,param1);
|
||||
hexprint_byte_sep((uint8_t)(param2>>8));
|
||||
hexprint_byte((uint8_t)param2);
|
||||
W("\n\r");
|
||||
print_executing();
|
||||
sha204.wakeup(rx_buffer);
|
||||
r = sha204.lock(tx_buffer, rx_buffer, param1, param2);
|
||||
if(idle) { sha204.idle(); } else { sha204.sleep(); }
|
||||
print_return_code(r);
|
||||
print_received_from_sha(rx_buffer);
|
||||
break;
|
||||
case '\r': // enter
|
||||
case '?': // help
|
||||
print_help();
|
||||
break;
|
||||
case 'I': // switch idle and sleep
|
||||
W("Switching whether the ATSHA should be put to sleep or to idle mode after commands.\n\rCurrent setting: ");
|
||||
if(idle) {
|
||||
idle = 0;
|
||||
Wl("Sleep.");
|
||||
}
|
||||
else {
|
||||
idle = 1;
|
||||
Wl("Idle.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Must throw away unused bytes from the host, or it will lock up while waiting for the device */
|
||||
//usb_serial_flush_input();
|
||||
|
||||
usb_tasks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Helper functions implementation */
|
||||
|
||||
void hexprint_byte(uint8_t b) {
|
||||
uint8_t high, low;
|
||||
low = b & 0xF;
|
||||
high = b >> 4;
|
||||
usb_serial_putchar(high+'0'+7*(high/10));
|
||||
usb_serial_putchar(low+'0'+7*(low/10));
|
||||
}
|
||||
|
||||
void hexprint_byte_sep(uint8_t b) {
|
||||
hexprint_byte(b);
|
||||
usb_serial_putchar(hexprint_separator);
|
||||
}
|
||||
|
||||
void hexprint_noln(uint8_t *p, uint16_t length) {
|
||||
for(uint16_t i=0; i<length; i++) {
|
||||
hexprint_byte(p[i]);
|
||||
if(hexprint_separator!=0)
|
||||
usb_serial_putchar(hexprint_separator);
|
||||
}
|
||||
}
|
||||
|
||||
void hexprint(uint8_t *p, uint16_t length) {
|
||||
hexprint_noln(p, length);
|
||||
usb_serial_write_P(PSTR("\n\r"));
|
||||
}
|
||||
|
||||
void hexprint_4bits(uint8_t b) {
|
||||
usb_serial_putchar((b&0xF)+'0'+7*((b&0xF)/10));
|
||||
}
|
||||
|
||||
void hexprint_1bit(uint8_t b) {
|
||||
usb_serial_putchar((b&1)+'0');
|
||||
}
|
||||
|
||||
void print_help(void) {
|
||||
Wl("*** SHA204 playground [(c) 2014 flabbergast] ***\n\r");
|
||||
Wl("Raw commands: wa[k]e [c]heckMAC [d]erive_key dev_re[v]ision [g]en_dig [h]MAC");
|
||||
Wl(" [m]ac [n]once [r]andom r[e]ad [w]rite [u]date_extra");
|
||||
Wl("Processed commands: [s]erial c[o]nfig_zone");
|
||||
Wl("Playground config: [I]dle-or-sleep");
|
||||
Wl("'?' -> this help");
|
||||
Wl("Dangerous/one-time only! [L]ock\n\r");
|
||||
Wl("Additional comments:");
|
||||
Wl(" - Format of ATSHA204 command responses:");
|
||||
Wl(" <1byte:packet_size> <msg_byte> <msg_byte> ... <1byte:crc_1> <1byte:crc_2>");
|
||||
Wl(" - ATSHA204 is sent to sleep or to idle mode after every command, select via [I].");
|
||||
Wl(" - The 'sent packet' info does not always match what's actually exactly sent. It's provided");
|
||||
Wl(" mainly to check the entered parameters.");
|
||||
Wl(" - Input, when requested, is expected in (padded) HEX format, e.g. 'AB01' for two bytes: 171 1.\n\r");
|
||||
}
|
||||
|
||||
void print_executing(void) {
|
||||
W("Executing: ");
|
||||
}
|
||||
|
||||
void print_received_from_sha(uint8_t *rx_buffer) {
|
||||
W("Received from ATSHA204: ");
|
||||
hexprint(rx_buffer, rx_buffer[0]);
|
||||
}
|
||||
|
||||
void print_execute_params(uint8_t opcode, uint8_t param1) {
|
||||
W("Will run with: opcode ");
|
||||
hexprint_byte_sep(opcode);
|
||||
W("param1 ");
|
||||
hexprint_byte_sep(param1);
|
||||
W("param2 ");
|
||||
}
|
||||
|
||||
uint8_t get_bytes_serial(uint8_t *output, uint16_t len) {
|
||||
char buffer[2*MAX_BUFFER_SIZE];
|
||||
uint16_t input_length;
|
||||
uint16_t i;
|
||||
uint8_t low, high;
|
||||
|
||||
input_length = usb_serial_readline(buffer, 2*len+1, false);
|
||||
strupr(buffer);
|
||||
for(i=0; i<input_length; i+=2) {
|
||||
high = buffer[i] - '0';
|
||||
if(high > 9)
|
||||
high -= 7;
|
||||
low = buffer[i+1] - '0';
|
||||
if(low > 9)
|
||||
low -= 7;
|
||||
output[i/2] = (uint8_t)(low + (high << 4));
|
||||
}
|
||||
|
||||
return (input_length/2);
|
||||
}
|
||||
|
||||
/* Read and Interpret ATSHA204 configuration */
|
||||
void process_config(uint8_t *config) {
|
||||
// serial number
|
||||
W("Serial number: ");
|
||||
hexprint_noln(config+ADDRESS_SN03, 4);
|
||||
hexprint(config+ADDRESS_SN47, 5);
|
||||
// revision number
|
||||
W("Revision number: ");
|
||||
hexprint(config+ADDRESS_RevNum,4);
|
||||
// I2C setup
|
||||
if(config[ADDRESS_I2CEN]&1) {
|
||||
W("I2C enabled; Address: ");
|
||||
hexprint_byte(config[ADDRESS_I2CADD]>>1);
|
||||
W("\n\r");
|
||||
} else {
|
||||
W("SingleWire (I2C disabled); TTL input level: ");
|
||||
if(config[ADDRESS_I2CADD]&0b1000)
|
||||
Wl("Vcc");
|
||||
else
|
||||
Wl("fixed");
|
||||
}
|
||||
// OTP mode
|
||||
W("OTP mode: ");
|
||||
switch(config[ADDRESS_OTPMODE]) {
|
||||
case 0xAA:
|
||||
Wl("read-only");
|
||||
break;
|
||||
case 0x55:
|
||||
Wl("consumption");
|
||||
break;
|
||||
case 0x00:
|
||||
Wl("legacy");
|
||||
break;
|
||||
default:
|
||||
Wl("reserved value (problem!)");
|
||||
break;
|
||||
}
|
||||
// selector mode
|
||||
W("Selector: ");
|
||||
if(!config[ADDRESS_SELECTOR])
|
||||
Wl("can be updated with UpdateExtra.");
|
||||
else
|
||||
Wl("can be updated only if it is 0.");
|
||||
// User extra
|
||||
W("User Extra byte: ");
|
||||
hexprint_byte(config[84]);
|
||||
W("\n\r");
|
||||
// Selector
|
||||
W("Selector byte: ");
|
||||
hexprint_byte(config[85]);
|
||||
W("\n\r");
|
||||
// Lock data
|
||||
W("Data and OTP zones are ");
|
||||
if(config[86]==0x55)
|
||||
Wl("unlocked.");
|
||||
else
|
||||
Wl("locked!");
|
||||
// Lock config
|
||||
W("Config zone is ");
|
||||
if(config[87]==0x55)
|
||||
Wl("unlocked.");
|
||||
else
|
||||
Wl("locked!");
|
||||
// Slots
|
||||
uint8_t i;
|
||||
Wl("Configurations of slots: ");
|
||||
for(i=0; i<16; i++) {
|
||||
uint8_t addr = 20+(2*i);
|
||||
W("Slot:");
|
||||
hexprint_4bits(i);
|
||||
W(" ReadKey:");
|
||||
hexprint_4bits(config[addr]); // getting the 2 config bytes LSB first
|
||||
W(" CheckOnly:");
|
||||
hexprint_1bit(config[addr]>>4);
|
||||
W(" SingleUse:");
|
||||
hexprint_1bit(config[addr]>>5);
|
||||
W(" EncryptRead:");
|
||||
hexprint_1bit(config[addr]>>6);
|
||||
W(" IsSecret:");
|
||||
hexprint_1bit(config[addr]>>7);
|
||||
W("\n\r WriteKey:");
|
||||
hexprint_4bits(config[addr+1]);
|
||||
W(" WriteConfig:");
|
||||
hexprint_4bits(config[addr+1]>>4);
|
||||
W("\n\r");
|
||||
if(i<8) { // slots 0-7 have extra data
|
||||
W(" UseFlag:");
|
||||
hexprint_byte(config[52+(2*i)]);
|
||||
W(" UpdateCount:");
|
||||
hexprint_byte(config[53+(2*i)]);
|
||||
W("\n\r");
|
||||
}
|
||||
if(i==15) { // slot15 has limit on usage
|
||||
W(" LastKeyUse: ");
|
||||
hexprint(config+68, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t receive_serial_binary_transaction(uint8_t *buffer, uint8_t len) {
|
||||
_delay_ms(100); // give the transmitting side the chance to push the rest through
|
||||
if( usb_serial_available() == 0 ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
uint8_t n_bytes = usb_serial_getchar();
|
||||
if( n_bytes >= len ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
buffer[0] = n_bytes;
|
||||
for(uint8_t i=1; i<=n_bytes; i++) {
|
||||
if( usb_serial_available() == 0 ) {
|
||||
return BINARY_TRANSACTION_RECEIVE_ERROR;
|
||||
}
|
||||
buffer[i] = (uint8_t)usb_serial_getchar();
|
||||
_delay_ms(3);
|
||||
}
|
||||
return BINARY_TRANSACTION_OK;
|
||||
}
|
||||
|
||||
uint8_t binary_mode_transaction(uint8_t *data, uint8_t rxsize, uint8_t *rx_buffer, SHA204SWI *sha204) {
|
||||
uint8_t i = 0;
|
||||
uint8_t len;
|
||||
uint8_t idle;
|
||||
uint8_t opcode;
|
||||
uint8_t param1;
|
||||
uint16_t param2;
|
||||
uint8_t datalen1=0;
|
||||
uint8_t data1[32];
|
||||
uint8_t datalen2=0;
|
||||
uint8_t data2[32];
|
||||
uint8_t datalen3=0;
|
||||
uint8_t data3[14];
|
||||
// process the input packet
|
||||
len = data[0];
|
||||
idle = data[1];
|
||||
if(len<5)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
opcode = data[2];
|
||||
param1 = data[3];
|
||||
param2 = data[4] + 256*data[5];
|
||||
if(len>5) {
|
||||
if((datalen1=data[6]) > 32)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen1; i++)
|
||||
data1[i] = data[7+i];
|
||||
}
|
||||
if(len>6+datalen1) {
|
||||
if((datalen2=data[7+datalen1]) > 32)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen2; i++)
|
||||
data2[i] = data[8+datalen1+i];
|
||||
}
|
||||
if(len>7+datalen1+datalen2) {
|
||||
if((datalen3=data[8+datalen1+datalen2]) > 13)
|
||||
return BINARY_TRANSACTION_PARAM_ERROR;
|
||||
for(i=0; i<datalen3; i++)
|
||||
data3[i] = data[9+datalen1+datalen2+i];
|
||||
}
|
||||
// run the transaction
|
||||
sha204->wakeup(data);
|
||||
i = sha204->execute(opcode, param1, param2,
|
||||
datalen1, data1, datalen2, data2, datalen3, data3,
|
||||
len, data, rxsize, rx_buffer);
|
||||
if(idle)
|
||||
sha204->idle();
|
||||
else
|
||||
sha204->sleep();
|
||||
if(i != SHA204_SUCCESS)
|
||||
return BINARY_TRANSACTION_EXECUTE_ERROR;
|
||||
return BINARY_TRANSACTION_OK;
|
||||
}
|
||||
|
||||
/* Return code stuff */
|
||||
|
||||
const char retcode_success[] PROGMEM = "Success.";
|
||||
const char retcode_parse_error[] PROGMEM = "Parse error.";
|
||||
const char retcode_cmd_fail[] PROGMEM = "Command execution error.";
|
||||
const char retcode_status_crc[] PROGMEM = "CRC error.";
|
||||
const char retcode_status_unknown[] PROGMEM = "Unknown error.";
|
||||
const char retcode_func_fail[] PROGMEM = "Couldn't execute due to wrong condition/state.";
|
||||
const char retcode_gen_fail[] PROGMEM = "Unspecified error.";
|
||||
const char retcode_bad_param[] PROGMEM = "Bad parameter.";
|
||||
const char retcode_invalid_id[] PROGMEM = "Invalid device ID.";
|
||||
const char retcode_invalid_size[] PROGMEM = "Out of range error.";
|
||||
const char retcode_bad_crc[] PROGMEM = "Bad CRC received.";
|
||||
const char retcode_rx_fail[] PROGMEM = "Timeout while waiting for a response (got >0 bytes).";
|
||||
const char retcode_rx_no_response[] PROGMEM = "Timeout (not an error while busy).";
|
||||
const char retcode_resync_with_wakeup[] PROGMEM = "Resync OK after wakeup.";
|
||||
const char retcode_comm_fail[] PROGMEM = "Communication failed";
|
||||
const char retcode_timeout[] PROGMEM = "Timeout while waiting for a response (got no bytes).";
|
||||
const char retcode_unknown[] PROGMEM = "Unknown error message.";
|
||||
|
||||
void print_return_code(uint8_t code) {
|
||||
const char *p PROGMEM;
|
||||
switch(code) {
|
||||
case(SHA204_SUCCESS):
|
||||
p = retcode_success;
|
||||
break;
|
||||
case(SHA204_PARSE_ERROR):
|
||||
p = retcode_parse_error;
|
||||
break;
|
||||
case(SHA204_CMD_FAIL):
|
||||
p = retcode_cmd_fail;
|
||||
break;
|
||||
case(SHA204_STATUS_CRC):
|
||||
p = retcode_status_crc;
|
||||
break;
|
||||
case(SHA204_STATUS_UNKNOWN):
|
||||
p = retcode_status_unknown;
|
||||
break;
|
||||
case(SHA204_FUNC_FAIL):
|
||||
p = retcode_func_fail;
|
||||
break;
|
||||
case(SHA204_GEN_FAIL):
|
||||
p = retcode_gen_fail;
|
||||
break;
|
||||
case(SHA204_BAD_PARAM):
|
||||
p = retcode_bad_param;
|
||||
break;
|
||||
case(SHA204_INVALID_ID):
|
||||
p = retcode_invalid_id;
|
||||
break;
|
||||
case(SHA204_INVALID_SIZE):
|
||||
p = retcode_invalid_size;
|
||||
break;
|
||||
case(SHA204_BAD_CRC):
|
||||
p = retcode_bad_crc;
|
||||
break;
|
||||
case(SHA204_RX_FAIL):
|
||||
p = retcode_rx_fail;
|
||||
break;
|
||||
case(SHA204_RX_NO_RESPONSE):
|
||||
p = retcode_rx_no_response;
|
||||
break;
|
||||
case(SHA204_RESYNC_WITH_WAKEUP):
|
||||
p = retcode_resync_with_wakeup;
|
||||
break;
|
||||
case(SHA204_COMM_FAIL):
|
||||
p = retcode_comm_fail;
|
||||
break;
|
||||
case(SHA204_TIMEOUT):
|
||||
p = retcode_timeout;
|
||||
break;
|
||||
default:
|
||||
p = retcode_unknown;
|
||||
break;
|
||||
}
|
||||
usb_serial_writeln_P(p);
|
||||
}
|
||||
|
1
talk_to_sha204/.gitignore
vendored
Normal file
1
talk_to_sha204/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
keys.ini
|
131
talk_to_sha204/README.md
Normal file
131
talk_to_sha204/README.md
Normal file
|
@ -0,0 +1,131 @@
|
|||
# talk_to_sha204.py
|
||||
|
||||
This python script gives access to some of the functionality of the
|
||||
ATSHA204, by talking to the `sha204_playground` firmware. It requires
|
||||
python 2.7, and its `pyserial` and `pyCrypto` libraries.
|
||||
|
||||
It was inspired by [hashlet] and sort-of emulates its functionality (and
|
||||
it's perhaps more buggy). The point is that [hashlet] requires a
|
||||
Raspberry Pi or a BeagleBone Black for talking to ATSHA204. This script
|
||||
talks to ATSHA204 chips through another ATMEL chip, e.g. Arduino, so it
|
||||
works on PCs and laptops as well (well, I haven't tried it on
|
||||
Windows...)
|
||||
|
||||
## Basic usage
|
||||
|
||||
Before explaining what various commands do, it is useful to have a look
|
||||
at [ATSHA204 datasheet]. Here's an excerpt: an ATSHA204's storage has 3
|
||||
parts: "configuration zone" (where ATSHA's configuration parameters are
|
||||
stored), "data zone" (where "keys" are stored), "OTP zone" (readable,
|
||||
but mostly not-writable area). These zones can be "unlocked" (factory
|
||||
state, things can be set up) or "locked" (when the zones are no longer
|
||||
writable (mostly), some keys can be also not-readable ("secret")).
|
||||
Locking is a one-time thing.
|
||||
|
||||
By "personalizing", I mean writing the desired configuration to ATSHA,
|
||||
locking the configuration zone, writing random keys to the data zone and
|
||||
locking it. There's space for 16 keys on an ATSHA, the access to them is
|
||||
governed individually by some settings stored in the config zone.
|
||||
|
||||
An important thing to understand is that once the data zone is locked,
|
||||
some keys will be not readable, or changeable, some will be readable and
|
||||
writable, some only in a complicated way ("encrypted read/write").
|
||||
So, when locking is done by this script, the keys are written to a file
|
||||
(`keys.ini` by default). It is a good idea to retain this file!
|
||||
|
||||
The list of all command-line parameters can be printed by
|
||||
|
||||
talk_to_sha204.py -h
|
||||
|
||||
The script talks to the firmware via a serial port: the path to the
|
||||
port can be either set on command line (`-s`) or in `talk_to_sha204.ini`
|
||||
config file.
|
||||
|
||||
One can set the verbosity of the output with the `-V` switch. Accepted
|
||||
values are `error`,`warning`,`info`,`debug`. Default is `error`, which
|
||||
means that the script is mostly silent and only informs about errors
|
||||
(which usually means the execution is interrupted). The `debug` level
|
||||
is relatively verbose about what's happening.
|
||||
|
||||
Here's a list of some commands accepted by `talk_to_sha204.py`:
|
||||
|
||||
### status
|
||||
|
||||
Prints 'factory' (nothing locked) or 'personalized' (everything locked)
|
||||
or 'neither' (config locked, data not).
|
||||
|
||||
### show_config
|
||||
|
||||
Prints the contents of the configuration zone of the ATSHA in a readable
|
||||
format (see the datasheet for explanation of the individual entries).
|
||||
|
||||
### personalize
|
||||
|
||||
This will write the configuration to ATSHA (see `personalize.ini` file),
|
||||
lock the config zone; then write keys to the data zone, something to the
|
||||
OTP zone and lock these zones.
|
||||
|
||||
The keys will be read from `keys.ini` file if it exists, any keys that
|
||||
can't be found will be generated randomly. All the keys will then be
|
||||
written to `keys.ini`.
|
||||
|
||||
The contents of the OTP zone can be configured in `personalize.ini`.
|
||||
|
||||
### random
|
||||
|
||||
This returns random 32 bytes (supplied by ATSHA). Note that before the
|
||||
configuration zone is locked, ATSHA returns always the same fixed bytes.
|
||||
|
||||
### mac
|
||||
|
||||
Generates a MAC digest from a file or stdin. The data used to compute
|
||||
the digest include the sha256 hash of the data (file or stdin) and one
|
||||
of secret keys stored on the ATSHA (so it can be verified only when one
|
||||
knows that secret key - so either on the ATSHA (see `check_mac`), or
|
||||
knowing the contents of the `keys.ini` file (see `offline_mac`).
|
||||
Example:
|
||||
|
||||
talk_to_sha204.py --file README.md mac
|
||||
|
||||
It returns something like:
|
||||
|
||||
data_sha256 : 94864636b6f0481d90d16229c07796a666ef377eeececeaa7d5d267ecdbd8787
|
||||
mac : 1ae94ec8bd41bb57d429a0603d57cd1fb7af75c09db44cb9172a008e93c4da8d
|
||||
|
||||
The first thing is the sha256 hash of the contents of the `README.md`
|
||||
file, this is then fed to ATSHA204 chip, which computes the resulting
|
||||
`mac`.
|
||||
|
||||
### check_mac
|
||||
|
||||
Used for verification of a MAC. The MAC and "challenge" (data used to
|
||||
compute the MAC in the first place; in our case it would be the
|
||||
`data_sha256` produced by the `mac` command). The script returns '0' on
|
||||
success and '1' on no-match or error. Silently. To see some output, we
|
||||
also need to increase the verbosity level to (at least) `info`.
|
||||
|
||||
talk_to_sha204.py --mac 1ae94ec8bd41bb57d429a0603d57cd1fb7af75c09db44cb9172a008e93c4da8d --challenge 94864636b6f0481d90d16229c07796a666ef377eeececeaa7d5d267ecdbd8787 --verbosity info check_mac
|
||||
|
||||
Result:
|
||||
|
||||
INFO:root:Response: match!
|
||||
|
||||
### offline_mac
|
||||
|
||||
The `check_mac` command uses ATSHA to verify the MAC. To verify the MAC
|
||||
without the chip, one needs to have the correct contents of `Slot0` in
|
||||
the `keys.ini` file; then `offline_mac` command can be used. Example:
|
||||
|
||||
talk_to_sha204.py --mac 1ae94ec8bd41bb57d429a0603d57cd1fb7af75c09db44cb9172a008e93c4da8d --challenge 94864636b6f0481d90d16229c07796a666ef377eeececeaa7d5d267ecdbd8787 --verbosity info offline_mac
|
||||
|
||||
Result:
|
||||
|
||||
INFO:root:Response: match!
|
||||
|
||||
The point is that this can be used on, say, a server without the ATSHA
|
||||
chip present (but with the `keys.ini` file available).
|
||||
|
||||
|
||||
|
||||
[hashlet]: https://github.com/cryptotronix/hashlet
|
||||
[ATSHA204 datasheet]: http://www.atmel.com/Images/Atmel-8740-CryptoAuth-ATSHA204-Datasheet.pdf
|
30
talk_to_sha204/personalize.ini
Normal file
30
talk_to_sha204/personalize.ini
Normal file
|
@ -0,0 +1,30 @@
|
|||
[ConfigZone]
|
||||
I2Cenable = no
|
||||
I2Caddress = 0x64
|
||||
# this OTPmode (0xAA - read-only) differs from the factory value (0x55 - consumption)
|
||||
OTPmode = 0xAA
|
||||
SelectorMode = 0x00
|
||||
|
||||
## example configuration for individual slots
|
||||
## can use [Slot0] to [Slot15]
|
||||
[Slot0]
|
||||
ReadKey = 15
|
||||
CheckOnly = False
|
||||
SingleUse = False
|
||||
EncryptRead = False
|
||||
IsSecret = True
|
||||
WriteConfig = 0b1000
|
||||
WriteKey = 0
|
||||
# the next two options only work for keys 0-7
|
||||
UseFlag = 0xff
|
||||
UpdateCount = 0x00
|
||||
# the next option only works with key 15 (note it should a hex string!)
|
||||
KeyUse = ffffffffffffffffffffffffffffffff
|
||||
# use 'keys.ini' file to specify slot contents if required
|
||||
|
||||
[OTPzone]
|
||||
OTPcontents = "flabbergast __DATE__ "
|
||||
## Notes for OTPcontents:
|
||||
## - expected form is a string enclosed in double quotes (")
|
||||
## - will be padded by 0xFF's to 64 bytes, or cut short if longer
|
||||
## - __DATE__ placeholder will be replaced by current date in YYYYMMDD format
|
3
talk_to_sha204/talk_to_sha204.ini
Normal file
3
talk_to_sha204/talk_to_sha204.ini
Normal file
|
@ -0,0 +1,3 @@
|
|||
[Communication]
|
||||
SerialPort = /dev/ttyACM0
|
||||
|
690
talk_to_sha204/talk_to_sha204.py
Executable file
690
talk_to_sha204/talk_to_sha204.py
Executable file
|
@ -0,0 +1,690 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
# talk_to_sha204.py
|
||||
# (c) 2014 flabbergast
|
||||
#
|
||||
# Communicate with ATSHA204 via the binary mode of sha204_playground firmware.
|
||||
#
|
||||
|
||||
import serial
|
||||
from Crypto.Hash import SHA256
|
||||
|
||||
import binascii
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import argparse
|
||||
import ConfigParser
|
||||
import pprint
|
||||
|
||||
BINARY_TRANSACTION_CODE = chr(0xFD)
|
||||
|
||||
# command op-code definitions
|
||||
SHA204_CHECKMAC = chr(0x28)
|
||||
SHA204_DERIVE_KEY = chr(0x1C)
|
||||
SHA204_DEVREV = chr(0x30)
|
||||
SHA204_GENDIG = chr(0x15)
|
||||
SHA204_HMAC = chr(0x11)
|
||||
SHA204_LOCK = chr(0x17)
|
||||
SHA204_MAC = chr(0x08)
|
||||
SHA204_NONCE = chr(0x16)
|
||||
SHA204_PAUSE = chr(0x01)
|
||||
SHA204_RANDOM = chr(0x1B)
|
||||
SHA204_READ = chr(0x02)
|
||||
SHA204_UPDATE_EXTRA = chr(0x20)
|
||||
SHA204_WRITE = chr(0x12)
|
||||
|
||||
# firmware binary mode return codes
|
||||
BINARY_MODE_RETURN_CODES = {
|
||||
0: 'BINARY_TRANSACTION_OK',
|
||||
1: 'BINARY_TRANSACTION_RECEIVE_ERROR',
|
||||
2: 'BINARY_TRANSACTION_PARAM_ERROR',
|
||||
3: 'BINARY_TRANSACTION_EXECUTE_ERROR',
|
||||
99: 'PROBLEM WITH SERIAL COMMUNICATION (BUFFERING?)'
|
||||
}
|
||||
|
||||
# idle versus sleep instruction
|
||||
REQUEST_IDLE = chr(1)
|
||||
REQUEST_SLEEP = chr(0)
|
||||
|
||||
# Parameters for MAC/checkMAC/offlineMAC
|
||||
MAC_SLOT = 0
|
||||
MAC_MODE = chr(0)
|
||||
def MAC_OTHER_DATA(slot):
|
||||
return SHA204_MAC+MAC_MODE+chr(slot)+b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
|
||||
|
||||
#########################################
|
||||
### Low-Level communication functions ###
|
||||
#########################################
|
||||
|
||||
def crc16(data):
|
||||
crc_register = 0
|
||||
polynomial = 0x8005
|
||||
for c in data:
|
||||
for shift_register in 1, 2, 4, 8, 16, 32, 64, 128:
|
||||
data_bit = 1 if (ord(c) & shift_register) > 0 else 0
|
||||
crc_bit = crc_register >> 15
|
||||
crc_register = (crc_register << 1) & 0xFFFF
|
||||
if (data_bit ^ crc_bit) != 0:
|
||||
crc_register ^= polynomial
|
||||
#return crc_register
|
||||
return chr(crc_register & 0xFF) + chr(crc_register >> 8)
|
||||
|
||||
|
||||
class TransactionError(Exception):
|
||||
def __init__(self, message, value=0):
|
||||
self.message = message
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.message + ': ' + BINARY_MODE_RETURN_CODES[self.value])
|
||||
|
||||
|
||||
def do_transaction(buf, serport):
|
||||
# buf is assumed to have the following format:
|
||||
# 1 byte: idle or sleep after command?
|
||||
# 1 byte: opcode
|
||||
# 1 byte: param1
|
||||
# 2 bytes: param2
|
||||
# --> from this point on, parameters go in pairs (length, data), and they are optional
|
||||
# 1 byte: datalen1
|
||||
# datalen1 bytes: data1
|
||||
# 1 byte: datalen2
|
||||
# datalen2 bytes: data2
|
||||
# 1 byte: datalen3
|
||||
# datalen3 bytes: data3
|
||||
if args.dry_run and buf[1] in [SHA204_WRITE, SHA204_LOCK, SHA204_UPDATE_EXTRA]:
|
||||
logging.info("Dry run! Not sending " + binascii.hexlify(buf))
|
||||
return chr(0)
|
||||
message = b'' + BINARY_TRANSACTION_CODE + chr(len(buf)) + buf
|
||||
serport.write(message)
|
||||
status = serport.read(1) # read on byte, with timeout
|
||||
if status != chr(0):
|
||||
raise TransactionError("Firmware returned", ord(status))
|
||||
response_length = ord(serport.read(1)) # next byte is message length, this byte included
|
||||
response = serport.read(response_length - 1) # read the rest of the message (timeout!)
|
||||
if len(response) != response_length - 1:
|
||||
raise TransactionError("Serial communication problem: did not receive the whole response", 99)
|
||||
crc = crc16(chr(response_length) + response[0:-2])
|
||||
if crc != response[-2:]:
|
||||
raise TransactionError("CRC error", 99)
|
||||
# flush the port to clean up the pipes
|
||||
serport.flushInput()
|
||||
serport.flushOutput()
|
||||
return response[0:-2]
|
||||
|
||||
|
||||
###############################
|
||||
### Mid-level communication ###
|
||||
###############################
|
||||
|
||||
def receive_config_area(serport):
|
||||
config = do_transaction(REQUEST_SLEEP+SHA204_READ + b'\x80\x00\x00', serport)
|
||||
config += do_transaction(REQUEST_SLEEP+SHA204_READ + b'\x80\x08\x00', serport)
|
||||
for i in range(0x10, 0x16):
|
||||
config += do_transaction(REQUEST_SLEEP+SHA204_READ + b'\x00' + chr(i) + b'\x00', serport)
|
||||
return config
|
||||
|
||||
|
||||
def read_config_area(serport):
|
||||
logging.debug("Reading and processing config area of ATSHA...")
|
||||
try:
|
||||
return receive_config_area(serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
|
||||
|
||||
def write_config_word(address, word, serport):
|
||||
if len(word) != 4:
|
||||
logging.error("Trying to write something else that 4 bytes to config area!")
|
||||
exit(1)
|
||||
logging.debug("Writing to config zone, word address " + hex(address) + ", word: 0x" + binascii.hexlify(word))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_WRITE + b'\x00' + chr(address) + b'\x00\x04' + word, serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
return response
|
||||
|
||||
|
||||
def write_otp_area(contents, serport):
|
||||
if len(contents) != 64:
|
||||
logging.error("Trying to write something else that 64 bytes to OTP!")
|
||||
exit(1)
|
||||
logging.debug("Writing to OTP zone, word address 0x0, data: 0x" + binascii.hexlify(contents[0:32]))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_WRITE + b'\x81\x00\x00\x20' + contents[0:32], serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
logging.debug("Writing to OTP zone, word address 0x8, data: 0x" + binascii.hexlify(contents[32:64]))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_WRITE + b'\x81\x08\x00\x20' + contents[32:64], serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
return response
|
||||
|
||||
|
||||
def update_config_area(config, serport):
|
||||
config_new = process_config_modifications(config)
|
||||
# determine differences and write them
|
||||
for i in range(0, 22):
|
||||
have_changed = False
|
||||
for j in range(0, 4):
|
||||
if config_new[4 * i + j] != config[4 * i + j]:
|
||||
logging.info("Changing byte in config zone at position " + hex(4 * i + j) + ", from " + hex(
|
||||
ord(config[4 * i + j])) + " to " + hex(ord(config_new[4 * i + j])))
|
||||
have_changed = True
|
||||
if have_changed:
|
||||
write_config_word(i, config_new[4 * i:4 * i + 4], serport)
|
||||
return config_new
|
||||
|
||||
|
||||
def do_lock_config_area(expected_config, serport):
|
||||
logging.info("Verifying the config zone contents.")
|
||||
config_verify = read_config_area(ser_port)
|
||||
if not (expected_config == config_verify):
|
||||
logging.error(
|
||||
"The contents of the config zone is not what is expected! Problem with ATSHA or dry run? Not locking.")
|
||||
exit(1)
|
||||
else:
|
||||
logging.info("Locking the config zone!")
|
||||
crc = crc16(expected_config)
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_LOCK + b'\x00' + crc, serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
return response
|
||||
|
||||
|
||||
def do_lock_data_otp_area(expected_data, expected_otp, serport):
|
||||
logging.info("Locking the data and OTP zones!")
|
||||
crc = crc16(expected_data + expected_otp)
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_LOCK + b'\x01' + crc, serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
return response
|
||||
|
||||
|
||||
def get_random(serport):
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_RANDOM + b'\x00\x00\x00', serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
return response
|
||||
|
||||
|
||||
def write_data_slot(slot, contents, serport):
|
||||
if len(contents) != 32 or slot < 0 or slot > 15:
|
||||
logging.error("Something went wrong, the call to write_data_slot has wrong params!")
|
||||
exit(1)
|
||||
logging.debug("Writing to data zone, slot " + hex(slot) + ", data: 0x" + binascii.hexlify(contents))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_WRITE + b'\x82' + chr(slot * 8) + b'\x00\x20' + contents, serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
logging.debug("Got response: " + ("OK" if response == chr(0) else "not OK"))
|
||||
return response
|
||||
|
||||
|
||||
def mac(challenge, slot, serport):
|
||||
if len(challenge) != 32 or slot < 0 or slot > 15:
|
||||
logging.error("Something went wrong, the call to mac has wrong params!")
|
||||
exit(1)
|
||||
logging.debug("Calling the mac command, challenge "+binascii.hexlify(challenge)+", slot "+hex(slot))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_MAC+MAC_MODE+chr(slot)+b'\x00\x20' + challenge, serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
if len(response) != 32:
|
||||
logging.error("Received an unexpected response from mac command: "+binascii.hexlify(response))
|
||||
else:
|
||||
print("data_sha256 : "+binascii.hexlify(challenge))
|
||||
print("mac : "+binascii.hexlify(response))
|
||||
|
||||
def check_mac(challenge, mac, slot, serport):
|
||||
if len(challenge) != 32 or len(mac) != 32 or slot < 0 or slot > 15:
|
||||
logging.error("Something went wrong, the call to mac has wrong params!")
|
||||
exit(1)
|
||||
logging.debug("Calling the checkmac command, challenge "+binascii.hexlify(challenge)+", mac "+binascii.hexlify(mac)+" slot "+hex(slot))
|
||||
try:
|
||||
response = do_transaction(REQUEST_SLEEP+SHA204_CHECKMAC+MAC_MODE+chr(slot)+b'\x00\x20' + challenge + b'\x20' + mac + b'\x0D' + MAC_OTHER_DATA(slot), serport)
|
||||
except TransactionError, e:
|
||||
logging.error("ERROR communicating with firmware/ATSHA: " + str(e))
|
||||
exit(1)
|
||||
else:
|
||||
if response == chr(0):
|
||||
logging.info("Response: match!");
|
||||
exit(0)
|
||||
else:
|
||||
logging.info("Response: no match!");
|
||||
exit(1)
|
||||
|
||||
#######################
|
||||
### Data processing ###
|
||||
#######################
|
||||
|
||||
def process_config_area(config):
|
||||
c = {'serial': binascii.hexlify(config[0:4] + config[8:13]), 'revision': binascii.hexlify(config[4:8]),
|
||||
'I2Cenable': (ord(config[14]) & 1 == 1), 'I2Caddress': hex(ord(config[16]) >> 1)}
|
||||
if config[18] == b'\xAA':
|
||||
c['OTPmode'] = "read-only"
|
||||
elif config[18] == b'\x55':
|
||||
c['OTPmode'] = "consumption"
|
||||
elif config[18] == b'\x00':
|
||||
c['OTPmode'] = "legacy"
|
||||
else:
|
||||
c['OTPmode'] = "error!"
|
||||
if config[19] == b'\x00':
|
||||
c['SelectorMode'] = "Selector can be updated with UpdateExtra"
|
||||
else:
|
||||
c['SelectorMode'] = "Selector can be updated only when 0"
|
||||
c['UserExtra'] = binascii.hexlify(config[84])
|
||||
c['Selector'] = binascii.hexlify(config[85])
|
||||
c['DataOTPlocked'] = (config[86] != b'\x55')
|
||||
c['ConfigLocked'] = (config[87] != b'\x55')
|
||||
c['slotConfigs'] = []
|
||||
for i in range(0, 16):
|
||||
slot = {'Index': i, 'ReadKey': ord(config[20 + 2 * i]) & 0xF,
|
||||
'CheckOnly': (ord(config[20 + 2 * i]) & (1 << 4) > 0),
|
||||
'SingleUse': (ord(config[20 + 2 * i]) & (1 << 5) > 0),
|
||||
'EncryptRead': (ord(config[20 + 2 * i]) & (1 << 6) > 0),
|
||||
'IsSecret': (ord(config[20 + 2 * i]) & (1 << 7) > 0), 'WriteKey': ord(config[21 + 2 * i]) & 0xF,
|
||||
'WriteConfig': b'0b' + bin((ord(config[21 + 2 * i]) & 0xF0) >> 4)[2:].zfill(4)}
|
||||
if i < 8:
|
||||
slot['UseFlag'] = binascii.hexlify(config[52 + 2 * i])
|
||||
slot['UpdateCount'] = binascii.hexlify(config[53 + 2 * i])
|
||||
if i == 15:
|
||||
slot['KeyUse'] = binascii.hexlify(config[68:84])
|
||||
c['slotConfigs'].append(slot)
|
||||
return c
|
||||
|
||||
|
||||
def get_ini_bool(ini, section, option):
|
||||
try:
|
||||
t = ini.getboolean(section, option)
|
||||
except ValueError:
|
||||
logging.error("[" + section + "]->" + option + " value can't be parsed correctly from the config file.")
|
||||
return None
|
||||
else:
|
||||
return t
|
||||
|
||||
|
||||
def get_ini_int(ini, section, option, possibilites=range(0, 256)):
|
||||
try:
|
||||
t = int(ini.get(section, option), 0)
|
||||
except ValueError:
|
||||
logging.error("[" + section + "]->" + option + " value can't be parsed correctly from the config file.")
|
||||
return None
|
||||
else:
|
||||
if t not in possibilites:
|
||||
logging.error("[" + section + "]->" + option + " value can't be parsed correctly from the config file.")
|
||||
return None
|
||||
else:
|
||||
return t
|
||||
|
||||
|
||||
def get_ini_str(ini, section, option, validate=(lambda x: True)):
|
||||
try:
|
||||
t = ini.get(section, option)
|
||||
except ValueError:
|
||||
logging.error("[" + section + "]->" + option + " value can't be parsed correctly from the config file.")
|
||||
return None
|
||||
else:
|
||||
if not validate(t):
|
||||
logging.error("[" + section + "]->" + option + " value can't be parsed correctly from the config file.")
|
||||
return None
|
||||
else:
|
||||
return t
|
||||
|
||||
|
||||
def validate_hexlified_data(string, length):
|
||||
try:
|
||||
t = binascii.unhexlify(string)
|
||||
except TypeError:
|
||||
return False
|
||||
else:
|
||||
if len(t) != length:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def validate_key_use(key_use):
|
||||
return validate_hexlified_data(key_use, 16)
|
||||
|
||||
|
||||
def validate_slot_contents(contents):
|
||||
return validate_hexlified_data(contents, 32)
|
||||
|
||||
|
||||
def process_config_modifications(config):
|
||||
if len(config) != 88:
|
||||
logging.error("Something's wrong with the config (incorrect length?).")
|
||||
exit(1)
|
||||
personalize_config = ConfigParser.SafeConfigParser()
|
||||
if os.path.isfile(args.personalize_file):
|
||||
personalize_config.read(args.personalize_file)
|
||||
else:
|
||||
logging.warning("Personalize file not found. Proceeding with current ATSHA configuration.")
|
||||
return config
|
||||
config_list = list(config)
|
||||
if personalize_config.has_option('ConfigZone', 'I2Cenable'):
|
||||
t = get_ini_bool(personalize_config, 'ConfigZone', 'I2Cenable')
|
||||
if t is not None:
|
||||
config_list[14] = (chr(1) if t else chr(0))
|
||||
if personalize_config.has_option('ConfigZone', 'I2Caddress'):
|
||||
t = get_ini_int(personalize_config, 'ConfigZone', 'I2Caddress', range(0, 128))
|
||||
if t is not None:
|
||||
config_list[16] = chr(t << 1)
|
||||
if personalize_config.has_option('ConfigZone', 'OTPmode'):
|
||||
t = get_ini_int(personalize_config, 'ConfigZone', 'OTPmode', [0xAA, 0x55, 0])
|
||||
if t is not None:
|
||||
config_list[18] = chr(t)
|
||||
if personalize_config.has_option('ConfigZone', 'SelectorMode'):
|
||||
t = get_ini_int(personalize_config, 'ConfigZone', 'SelectorMode')
|
||||
if t is not None:
|
||||
config_list[19] = chr(t)
|
||||
for i in range(0, 16):
|
||||
slot_sect = 'Slot' + str(i)
|
||||
slot_addr = 20 + 2 * i
|
||||
if personalize_config.has_section(slot_sect):
|
||||
if personalize_config.has_option(slot_sect, 'ReadKey'):
|
||||
t = get_ini_int(personalize_config, slot_sect, 'ReadKey', range(0, 16))
|
||||
if t is not None:
|
||||
config_list[slot_addr] = chr((ord(config_list[slot_addr]) & 0xF0) | t)
|
||||
if personalize_config.has_option(slot_sect, 'CheckOnly'):
|
||||
t = get_ini_bool(personalize_config, slot_sect, 'CheckOnly')
|
||||
if t is not None:
|
||||
if t:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) | (1 << 4))
|
||||
else:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) & (0xFF & ~(1 << 4)))
|
||||
if personalize_config.has_option(slot_sect, 'SingleUse'):
|
||||
t = get_ini_bool(personalize_config, slot_sect, 'SingleUse')
|
||||
if t is not None:
|
||||
if t:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) | (1 << 5))
|
||||
else:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) & (0xFF & ~(1 << 5)))
|
||||
if personalize_config.has_option(slot_sect, 'EncryptRead'):
|
||||
t = get_ini_bool(personalize_config, slot_sect, 'EncryptRead')
|
||||
if t is not None:
|
||||
if t:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) | (1 << 6))
|
||||
else:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) & (0xFF & ~(1 << 6)))
|
||||
if personalize_config.has_option(slot_sect, 'IsSecret'):
|
||||
t = get_ini_bool(personalize_config, slot_sect, 'IsSecret')
|
||||
if t is not None:
|
||||
if t:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) | (1 << 7))
|
||||
else:
|
||||
config_list[slot_addr] = chr(ord(config_list[slot_addr]) & (0xFF & ~(1 << 7)))
|
||||
if personalize_config.has_option(slot_sect, 'WriteKey'):
|
||||
t = get_ini_int(personalize_config, slot_sect, 'WriteKey', range(0, 16))
|
||||
if t is not None:
|
||||
config_list[slot_addr + 1] = chr((ord(config_list[slot_addr + 1]) & 0xF0) | t)
|
||||
if personalize_config.has_option(slot_sect, 'WriteConfig'):
|
||||
t = get_ini_int(personalize_config, slot_sect, 'WriteConfig', range(0, 16))
|
||||
if t is not None:
|
||||
config_list[slot_addr + 1] = chr((ord(config_list[slot_addr + 1]) & 0x0F) | (t << 4))
|
||||
if i < 8:
|
||||
useflag_addr = 52 + 2 * i
|
||||
if personalize_config.has_option(slot_sect, 'UseFlag'):
|
||||
t = get_ini_int(personalize_config, slot_sect, 'UseFlag')
|
||||
if t is not None:
|
||||
config_list[useflag_addr] = chr(t)
|
||||
if personalize_config.has_option(slot_sect, 'UpdateCount'):
|
||||
t = get_ini_int(personalize_config, slot_sect, 'UpdateCount')
|
||||
if t is not None:
|
||||
config_list[useflag_addr + 1] = chr(t)
|
||||
if i == 15:
|
||||
if personalize_config.has_option(slot_sect, 'KeyUse'):
|
||||
t = get_ini_str(personalize_config, slot_sect, 'KeyUse', validate_key_use)
|
||||
if t is not None:
|
||||
t = binascii.unhexlify(t)
|
||||
for j in range(0, 16):
|
||||
config_list[68 + j] = t[j]
|
||||
return b''.join(config_list)
|
||||
|
||||
|
||||
#########################
|
||||
### Command functions ###
|
||||
#########################
|
||||
|
||||
def lock_config(serport):
|
||||
config_bin = read_config_area(serport)
|
||||
config_area = process_config_area(config_bin)
|
||||
if config_area['ConfigLocked']:
|
||||
logging.error("Config zone already locked!")
|
||||
exit(1)
|
||||
config_bin_new = update_config_area(config_bin, serport)
|
||||
if chr(0) == do_lock_config_area(config_bin_new, serport):
|
||||
print "Config zone locked!"
|
||||
|
||||
|
||||
def lock_data(serport):
|
||||
config_area = process_config_area(read_config_area(serport))
|
||||
if not config_area['ConfigLocked']:
|
||||
logging.error("Config zone needs to be locked before locking data and OTP!")
|
||||
exit(1)
|
||||
elif config_area['DataOTPlocked']:
|
||||
logging.error("Data and OTP zones are already locked!")
|
||||
exit(1)
|
||||
keys = {}
|
||||
keys_ini = ConfigParser.ConfigParser()
|
||||
# read keys from file if present
|
||||
if (not args.random_keys) and os.path.isfile(args.keys_file):
|
||||
keys_ini.read(args.keys_file)
|
||||
for i in range(0, 16):
|
||||
if keys_ini.has_option('Keys', 'Slot' + str(i)):
|
||||
t = get_ini_str(keys_ini, 'Keys', 'Slot' + str(i), validate_slot_contents)
|
||||
if t is not None:
|
||||
keys[i] = binascii.unhexlify(t)
|
||||
logging.info("Read " + str(len(keys)) + " from " + args.keys_file)
|
||||
# fill in the other ones randomly
|
||||
for i in range(0, 16):
|
||||
if i not in keys:
|
||||
keys[i] = get_random(serport)
|
||||
# prepare ini for writing
|
||||
if not keys_ini.has_section('Keys'):
|
||||
keys_ini.add_section('Keys')
|
||||
for i in range(0, 16):
|
||||
keys_ini.set('Keys', 'Slot' + str(i), binascii.hexlify(keys[i]))
|
||||
# write keys_ini
|
||||
with open(args.keys_file, 'w') as f:
|
||||
keys_ini.write(f)
|
||||
# write the keys into slots
|
||||
whole_data = b''
|
||||
for i in range(0, 16):
|
||||
write_data_slot(i, keys[i], serport)
|
||||
whole_data += keys[i] # collect all the slots into one variable, used later for locking
|
||||
# OTP stuff
|
||||
otp = b'\xFF' * 64
|
||||
if not os.path.isfile(args.personalize_file):
|
||||
logging.warning("Personalize file not found. OTP zone will be filled with 0xFF's.")
|
||||
else:
|
||||
personalize_config = ConfigParser.SafeConfigParser()
|
||||
personalize_config.read(args.personalize_file)
|
||||
if not personalize_config.has_option('OTPzone', 'OTPcontents'):
|
||||
logging.warning(
|
||||
"OTP zone contents not set in " + args.personalize_file + ". It will be filled with 0xFF's.")
|
||||
else:
|
||||
otp = get_ini_str(personalize_config, 'OTPzone', 'OTPcontents')[1:-1].replace('__DATE__', time.strftime('%Y%m%d'))[0:64].ljust(64, chr(0xFF))
|
||||
write_otp_area(otp, serport)
|
||||
# lock!
|
||||
if chr(0) == do_lock_data_otp_area(whole_data, otp, serport):
|
||||
print "Data+OTP zones locked!"
|
||||
|
||||
|
||||
def check_mac_offline(challenge, mac, slot):
|
||||
# try to get the key
|
||||
keys = {}
|
||||
keys_ini = ConfigParser.ConfigParser()
|
||||
if not os.path.isfile(args.keys_file):
|
||||
logging.error("Need the keys_file for offline MAC checking!")
|
||||
exit(1)
|
||||
keys_ini.read(args.keys_file)
|
||||
if not keys_ini.has_option('Keys', 'Slot' + str(slot)):
|
||||
logging.error("Need the slot "+hex(slot)+" contents in "+args.keys_file+" file for offline MAC checking!")
|
||||
exit(1)
|
||||
key = get_ini_str(keys_ini, 'Keys', 'Slot' + str(slot), validate_slot_contents)
|
||||
if key is None:
|
||||
logging.error("Need the slot "+hex(slot)+" contents in "+args.keys_file+" file to be valid for offline MAC checking!")
|
||||
exit(1)
|
||||
key = binascii.unhexlify(key)
|
||||
other_data = MAC_OTHER_DATA(slot)
|
||||
full_challenge = key + challenge + other_data[0:4]+(b'\x00'*8)+other_data[4:7]+b'\xEE'+other_data[7:11]+b'\x01\x23'+other_data[11:13]
|
||||
computed_mac = SHA256.new(full_challenge)
|
||||
if computed_mac.digest() == mac:
|
||||
logging.info("Response: match!");
|
||||
exit(0)
|
||||
else:
|
||||
logging.info("Response: no match!");
|
||||
exit(1)
|
||||
|
||||
|
||||
#################
|
||||
### Main code ###
|
||||
#################
|
||||
|
||||
# parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Talk to ATSHA204 using sha204_playground firmware.",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("command", choices=['status', 'show_config', 'lock_config', 'lock_data', 'personalize', 'random',
|
||||
'mac', 'check_mac', 'offline_mac'], help='Command')
|
||||
parser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true', help="Do not do actual write or lock.")
|
||||
parser.add_argument('-c', '--config-file', dest='config_file', nargs='?', default='talk_to_sha204.ini',
|
||||
help="Path to config file.")
|
||||
parser.add_argument('-s', '--serial-port', dest='serial_path', nargs='?', help='Path to serial port.')
|
||||
parser.add_argument('-p', '--personalize-file', dest='personalize_file', nargs='?', default='personalize.ini',
|
||||
help="Path to file with data for personalizing.")
|
||||
parser.add_argument('-k', '--keys-file', dest='keys_file', nargs='?', default='keys.ini',
|
||||
help="Path to file with slot contents (any new random keys will be added on personalize or lock_data).")
|
||||
parser.add_argument('--random-keys', dest='random_keys', action='store_true',
|
||||
help="Do not read keys-file even if present, generate random keys (keys-file will be overwritten!).")
|
||||
parser.add_argument('-f', '--file', dest='file', nargs='?', help="Path to file to be used for MAC. Uses stdin if no file given.")
|
||||
parser.add_argument('-m', '--mac', dest='mac', nargs='?', help="MAC to be checked; for check_mac or offline_mac.")
|
||||
parser.add_argument('-C', '--challenge', dest='challenge', nargs='?', help="SHA256 of data (challenge) for check_mac or offline_mac.")
|
||||
parser.add_argument('-V', '--verbosity', dest='verbosity', nargs='?', default='error',
|
||||
choices=['error', 'warning', 'info', 'debug'], help="Verbosity level.")
|
||||
args = parser.parse_args() # args are used as a global variable
|
||||
|
||||
# set up logging
|
||||
log_level = getattr(logging, args.verbosity.upper(), None)
|
||||
if not isinstance(log_level, int):
|
||||
raise ValueError('Invalid log level: %s' % args.verbosity)
|
||||
logging.basicConfig(level=log_level)
|
||||
|
||||
# parse config file
|
||||
script_config = ConfigParser.ConfigParser()
|
||||
if os.path.isfile(args.config_file):
|
||||
script_config.read(args.config_file)
|
||||
|
||||
# do offline operations before doing anything with the serial port
|
||||
if args.command == 'offline_mac':
|
||||
# get params
|
||||
try:
|
||||
checkmac_challenge = binascii.unhexlify(args.challenge)
|
||||
checkmac_mac = binascii.unhexlify(args.mac)
|
||||
if len(checkmac_mac) != 32 or len(checkmac_challenge) != 32:
|
||||
raise TypeError("Incorrect length (should be 32 bytes / 64 hex chars).")
|
||||
except TypeError, e:
|
||||
logging.error("Problem processing MAC (--mac) or challenge (--challenge) parameters: "+str(e))
|
||||
exit(1)
|
||||
else:
|
||||
check_mac_offline(checkmac_challenge, checkmac_mac, MAC_SLOT)
|
||||
|
||||
# open serial port
|
||||
serial_path = ''
|
||||
if script_config.has_option('Communication', 'SerialPort'):
|
||||
serial_path = script_config.get('Communication', 'SerialPort')
|
||||
if args.serial_path:
|
||||
serial_path = args.serial_path
|
||||
if not os.path.exists(serial_path):
|
||||
logging.error("Specify a valid path to serial port either in the config file or on command line!")
|
||||
exit(1)
|
||||
ser_port = serial.Serial(port=serial_path, baudrate=115200, timeout=2) # timeout 2 seconds!
|
||||
time.sleep(2) # putting 2 so that Arduinos have time to run the bootloader, exit from it and start the sketch
|
||||
# for avr-gcc/LUFA, 0.5 is enough
|
||||
ser_port.flushInput() # throw away the message received after connecting (DTR)
|
||||
|
||||
# pretty printer
|
||||
pp = pprint.PrettyPrinter(indent=2)
|
||||
|
||||
if args.command == "show_config":
|
||||
config_area = process_config_area(read_config_area(ser_port))
|
||||
pp.pprint(config_area)
|
||||
exit(0)
|
||||
elif args.command == "status":
|
||||
config_area = process_config_area(read_config_area(ser_port))
|
||||
logging.info("Data and OTP: " + ("locked" if config_area['DataOTPlocked'] else "unlocked"))
|
||||
logging.info("Config area: " + ("locked" if config_area['ConfigLocked'] else "unlocked"))
|
||||
if config_area['DataOTPlocked'] and config_area['ConfigLocked']:
|
||||
print("personalized")
|
||||
elif not config_area['DataOTPlocked'] and not config_area['ConfigLocked']:
|
||||
print("factory")
|
||||
else:
|
||||
print("neither")
|
||||
exit(0)
|
||||
elif args.command == 'lock_config':
|
||||
lock_config(ser_port)
|
||||
elif args.command == 'random':
|
||||
print(binascii.hexlify(get_random(ser_port)))
|
||||
elif args.command == 'lock_data':
|
||||
lock_data(ser_port)
|
||||
elif args.command == 'personalize':
|
||||
config_area = process_config_area(read_config_area(ser_port))
|
||||
if not config_area['ConfigLocked']:
|
||||
lock_config(ser_port)
|
||||
if not config_area['DataOTPlocked']:
|
||||
lock_data(ser_port)
|
||||
print("personalized")
|
||||
elif args.command == 'mac':
|
||||
mac_challenge = SHA256.new()
|
||||
with open(args.file,'r') if args.file else sys.stdin as f:
|
||||
while True:
|
||||
chunk = f.read(8192)
|
||||
if len(chunk) == 0:
|
||||
break
|
||||
mac_challenge.update(chunk)
|
||||
mac(mac_challenge.digest(), MAC_SLOT, ser_port)
|
||||
elif args.command == 'check_mac':
|
||||
try:
|
||||
checkmac_challenge = binascii.unhexlify(args.challenge)
|
||||
checkmac_mac = binascii.unhexlify(args.mac)
|
||||
if len(checkmac_mac) != 32 or len(checkmac_challenge) != 32:
|
||||
raise TypeError("Incorrect length (should be 32 bytes / 64 hex chars).")
|
||||
except TypeError, e:
|
||||
logging.error("Problem processing MAC (--mac) or challenge (--challenge) parameters: "+str(e))
|
||||
exit(1)
|
||||
else:
|
||||
check_mac(checkmac_challenge, checkmac_mac, MAC_SLOT, ser_port)
|
||||
|
||||
|
||||
|
||||
exit(0)
|
Loading…
Reference in a new issue