diff --git a/SW/libs/.gitignore b/SW/libs/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..8402f28708a3b5199bce33ed32fb6797af661894 --- /dev/null +++ b/SW/libs/.gitignore @@ -0,0 +1,29 @@ +*.[oad] +*~ +*.mk +*.elf +*.lss +*.map +*.srec +*makefile* +*.b#* +*.s#* +*.asc +*.epf +*.pro +*.cproject +*.project +*.atsln +*.atsuo +*.cppproj +*.epp +*.db +*.d +*.o +*.mk +*.elf +*.lss +*.map +*.srec +.idea/ +build/ diff --git a/SW/libs/CMakeLists.txt b/SW/libs/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b0d2c477f4af1c6fe43214b22d6c9256b66d472 --- /dev/null +++ b/SW/libs/CMakeLists.txt @@ -0,0 +1,41 @@ +set(LIB_FILES + src/adc.cpp + src/adc.h + src/external_interrupt.h + src/jtag.cpp + src/jtag.h + src/MCP2515.cpp + src/MCP2515.h + src/MFRC522.cpp + src/MFRC522.h + src/spi.cpp + src/spi.h + src/usart.cpp + src/usart.h + src/wait.cpp + src/wait.h + src/macros.h + src/fifo.h + src/cplusplus.h + src/cplusplus.cpp + src/gpio.h + src/circularbuffer.h + ) + +if((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a")) + set(LIB_FILES ${LIB_FILES} + src/external_interrupt/ext_irq_m8.h + src/external_interrupt/ext_irq_m8.cpp) +elseif((${AVR_MCU} STREQUAL atmega16) OR (${AVR_MCU} STREQUAL atmega16a) OR (${AVR_MCU} STREQUAL atmega32) OR (${AVR_MCU} STREQUAL atmega32a)) + set(LIB_FILES ${LIB_FILES} + src/external_interrupt/ext_irq_m32.h + src/external_interrupt/ext_irq_m32.cpp) +elseif((${AVR_MCU} STREQUAL "atmega128") OR (${AVR_MCU} STREQUAL "atmega128a") OR (${AVR_MCU} STREQUAL "atmega1281")) + set(LIB_FILES ${LIB_FILES} + src/external_interrupt/ext_irq_m128.h + src/external_interrupt/ext_irq_m128.cpp) +else((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a")) + message(FATAL_ERROR "Unsupported device ${AVR_MCU}") +endif((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a")) + +add_avr_library(rk ${LIB_FILES}) diff --git a/SW/libs/README.md b/SW/libs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..0b72655087451f6f94a3b002200422cb959153aa --- /dev/null +++ b/SW/libs/README.md @@ -0,0 +1,21 @@ +## AVR knihovny ## + +*** +### Build ### +```bash +cd rk-avr-libs +mkdir build && cd build +cmake .. +make +``` +*** +### Install Fedora only +`./install.sh` + +*** +### ProblĂ©my +- v knihovnách nelze pouĹľĂvat makra → + - vÄ›ci jako F_CPU se musĂ Ĺ™ešit pĹ™es API knihovny + - podobÄ› u SPI, kde je nastavovánĂ pinĹŻ pro jednotlivĂ© druhy atmeg Ĺ™ešeno pĹ™es #define +- nevĂm, jestli se musĂ u knihovny specifikovat typ MCU → nastává problĂ©m se definicemi pinĹŻ a registrĹŻ +- wait example nejde zkmpompilovat... nechápu... diff --git a/SW/libs/examples/uart/CMakeLists.txt b/SW/libs/examples/uart/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f71ad710366a90f8c4d30a0df75e1fbeb0796fdd --- /dev/null +++ b/SW/libs/examples/uart/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.0) + +project(uart_example) + +set(AVR_UPLOADTOOL avrdude) +set(AVR_PROGRAMMER usbasp) +set(AVR_UPLOADTOOL_PORT usb) +set(AVR_MCU atmega8) +set(AVR_H_FUSE 0xd9) +set(AVR_L_FUSE 0xe4) +set(CMAKE_BUILD_TYPE Release) +set(MCU_SPEED "1000000UL") +set(WITH_MCU OFF) +set(WITH_MCU OFF CACHE BOOL "Add the mCU type to the target file name." FORCE) + +find_package(avr) + +add_definitions("-fpack-struct") +add_definitions("-fshort-enums") +add_definitions("-Wall") +add_definitions("-funsigned-char") +add_definitions("-funsigned-bitfields") +add_definitions("-ffunction-sections") +add_definitions("-c") +add_definitions("-std=c++14") + +#SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +set(SOURCE_FILES main.cpp) + +include_directories(../../src) +add_subdirectory(../../ rk) + +add_avr_executable(uart_example ${SOURCE_FILES}) +avr_target_link_libraries(uart_example rk) diff --git a/SW/libs/examples/uart/main.cpp b/SW/libs/examples/uart/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2f09c0c23f48168fda6a91ecf43d7ed66e7a7b7 --- /dev/null +++ b/SW/libs/examples/uart/main.cpp @@ -0,0 +1,31 @@ +#include <avr/io.h> +#include "usart.h" + +int main() +{ + //VytvoĹ™enĂ objektu uart + usart uart; + + //NastavenĂ uartu + uart.set_operating_mode(ASYNCHRONOUS_NORMAL); + uart.set_baudrate(4800); + uart.set_data_bits(8); + uart.set_stop_bits(1); + uart.set_parity(PARITY_NONE); + uart.enable_reciver(true); + uart.enable_trasmitter(true); + + //OdeslánĂ textovĂ©ho Ĺ™etÄ›zce + uart.transmit_string("\n\rHello world!\n\r"); + + char znak; + + for(;;) + { + //PĹ™ijmi znak + znak = uart.receive_char(); + + //Odešli znak zpátky + uart.transmit_char(znak); + } +} \ No newline at end of file diff --git a/SW/libs/examples/wait/CMakeLists.txt b/SW/libs/examples/wait/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..934a42df0517811a732ea6cdb61c55bf79a74493 --- /dev/null +++ b/SW/libs/examples/wait/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.0) + +project(wait_example) + +set(AVR_UPLOADTOOL avrdude) +set(AVR_PROGRAMMER usbasp) +set(AVR_UPLOADTOOL_PORT usb) +set(AVR_MCU atmega8) +set(AVR_H_FUSE 0xd9) +set(AVR_L_FUSE 0xe4) +set(CMAKE_BUILD_TYPE Release) +set(MCU_SPEED "1000000UL") +set(WITH_MCU OFF) +set(WITH_MCU OFF CACHE BOOL "Add the mCU type to the target file name." FORCE) + +find_package(avr) + +add_definitions("-fpack-struct") +add_definitions("-fshort-enums") +add_definitions("-Wall") +add_definitions("-funsigned-char") +add_definitions("-funsigned-bitfields") +add_definitions("-ffunction-sections") +add_definitions("-c") +add_definitions("-std=c++14") + +#SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +set(SOURCE_FILES main.cpp) + +include_directories(../../src) +add_subdirectory(../../ rk) + +add_avr_executable(wait_example ${SOURCE_FILES}) +avr_target_link_libraries(wait_example rk) diff --git a/SW/libs/examples/wait/main.cpp b/SW/libs/examples/wait/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3384607e16d043be26a8c1f8d794a7dfdcabfa2 --- /dev/null +++ b/SW/libs/examples/wait/main.cpp @@ -0,0 +1,19 @@ +#include <avr/io.h> +#include "wait.h" + + +int main() +{ + DDRC |= (1<<PC5); + + //NastavenĂ frekvence MCU pro metody wait (F_CPU se nastavuje v CMakeLists.txt) + w.set_f_cpu(F_CPU); + + for(;;) + { + PORTC ^= (1<<PC5); + + //ÄŚekej 250ms + w.wait_ms(250); + } +} \ No newline at end of file diff --git a/SW/libs/install.sh b/SW/libs/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..b1763e5c54ab46cc77c1e5391de5ad847ded1482 --- /dev/null +++ b/SW/libs/install.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Make sure only root can run our script +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit 1 +fi + +if [ ! -d /usr/avr/rk ]; then + sudo mkdir /usr/avr/include/rk +fi + +cp src/* /usr/avr/rk/ + +echo Done diff --git a/SW/libs/src/MCP2515.cpp b/SW/libs/src/MCP2515.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3249c23478e3f19ff6c223a7a93ca95a5b709ef1 --- /dev/null +++ b/SW/libs/src/MCP2515.cpp @@ -0,0 +1,324 @@ +/* +* MCP2515.cpp +* +* Created: 5.2.2014 19:53:58 +* Author: MTV +*/ + + +#include "MCP2515.h" +#include "wait.h" +#include "fifo.h" + +//spi_select_class spi(&DDRB, &PORTB, PB4); + + +// default constructor +MCP2515::MCP2515(spi_class &spi): spi(spi) +{ + //spi_ini(); + //reset(); +} //MCP2515 + +// default destructor +MCP2515::~MCP2515() +{ +} //~MCP2515 + +//Inizializace SPI rozhrani +void MCP2515::spi_ini(void) +{ + spi.set_operating_mode(spi.MASTER); + spi.enable_SPI(); + spi.set_data_order(spi.MSB); + spi.set_data_mode(spi.DATA_MODE_0); + spi.set_clock_rate(spi.F_OSC_2); +} //void spi_ini(void) + +////////////////////////////////////////////////////////////////////////// +/////////////////////////////Inicializace///////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void MCP2515::set_baudrate(uint8_t CNF1_val, uint8_t CNF2_val, uint8_t CNF3_val) +{ + spi.select(true); + + spi.write_data(SPI_WRITE); + spi.write_data(CNF3); + spi.write_data(CNF3_val); + spi.write_data(CNF2_val); + spi.write_data(CNF1_val); + + spi.select(false); +} //void set_baudrate(uint8_t CNF1_val, uint8_t CNF3_val, uint8_t CNF2_val) + +void MCP2515::set_RX0BF_pin(uint8_t mode) +{ + if (mode == RX_BUFFER_FULL_IRQ) modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE) | (1<<B0BFM)); + else if (mode == DIGITAL_OUTPUT) modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE)); + else if (mode == ON) modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE)); + else if (mode == OFF) modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE) | (1<<B0BFS)); + else modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), 0); //DISABLED +} //void set_RX0BF_pin(uint8_t mode) + +void MCP2515::set_RX1BF_pin(uint8_t mode) +{ + if (mode == RX_BUFFER_FULL_IRQ) modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE) | (1<<B1BFM)); + else if (mode == DIGITAL_OUTPUT) modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE)); + else if (mode == ON) modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE)); + else if (mode == OFF) modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE) | (1<<B1BFS)); + else modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), 0); //DISABLED +} //void set_RX1BF_pin(uint8_t mode) + +void MCP2515::set_CLKOUT_pin(uint8_t state, uint8_t prescaler /* = PRESCALER_8 */) +{ + if (state == CLKOUT_DISABLE) modify_bit(CANCTRL, (1<<CLKEN), 0); + else if (prescaler == PRESCALER_1) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN)); + else if (prescaler == PRESCALER_2) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE0)); + else if (prescaler == PRESCALER_4) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE1)); + else if (prescaler == PRESCALER_8) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE1) | (1<<CLKPRE0)); + else modify_bit(CANCTRL, (1<<CLKEN), 0); +} //void set_CLKOUT_pin(uint8_t state, uint8_t prescaler /* = PRESCALER_8 */) + +void MCP2515::set_operating_mode(uint8_t mode) +{ + if (mode == NORMAL_MODE) modify_bit(CANCTRL, 0xE0, 0); + else if (mode == SLEEP_MODE) modify_bit(CANCTRL, 0xE0, (1<<REQOP0)); + else if (mode == LOOPBACK_MODE) modify_bit(CANCTRL, 0xE0, (1<<REQOP1)); + else if (mode == LISTEN_ONLY_MODE) modify_bit(CANCTRL, 0xE0, (1<<REQOP0) | (1<<REQOP1)); + else if (mode == CONFIGURATION_MODE)modify_bit(CANCTRL, 0xE0, (1<<REQOP2)); + else ; +} //void set_operating_mode(uint8_t mode) + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////Obsluha/////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void MCP2515::write_register(uint8_t adress, uint8_t data) +{ + spi.select(true); + + spi.write_data(SPI_WRITE); + spi.write_data(adress); + spi.write_data(data); + + spi.select(false); +} //void write_register(uint8_t adress, uint8_t data) + +uint8_t MCP2515::read_register(uint8_t adress) +{ + uint8_t data; + + spi.select(true); + + spi.write_data(SPI_READ); + spi.write_data(adress); + + data = spi.write_and_read_data(0xff); + + spi.select(false); + + return data; +} //uint8_t read_register(uint8_t adress) + +void MCP2515::modify_bit(uint8_t adress, uint8_t mask, uint8_t data) +{ + spi.select(true); + + spi.write_data(SPI_BIT_MODIFY); + spi.write_data(adress); + spi.write_data(mask); + spi.write_data(data); + + spi.select(false); +} //void modify_bit(uint8_t adress, uint8_t mask, uint8_t data) + +uint8_t MCP2515::read_status(uint8_t type) +{ + uint8_t data; + + spi.select(true); + + spi.write_data(type); + data = spi.write_and_read_data(0xff); + + spi.select(false); + + return data; +} //uint8_t read_status(uint8_t type) + +uint8_t MCP2515::read_rx_status(void) +{ + uint8_t data; + + spi.select(true); + + spi.write_data(SPI_RX_STATUS); //Pozadavek na status + data = spi.write_and_read_data(0xff); //Precteni RX statusu +//spi.write_data(0xff); //MCP2515 porad posila status bajt + + spi.select(false); + + //return ((~data) & 0x20); //Vymaskovani spravneho bitu + //return ((~data) & 0x02); + return data; +} //uint8_t read_rx_status(void) + + +void MCP2515::reset() +{ + spi.select(true); + spi.write_data(SPI_RESET); + wait_ms(1); + spi.select(false); + wait_ms(50); +} + +void MCP2515::rx_handler(fifo<can_message> &rx_buffer) +{ + uint8_t buffer_1[14]; + uint8_t buffer_2[14]; + + buffer_1[0] = 0; + buffer_2[0] = 0; + + ////////////////////////////////////////////////////// + //Co je v bufferu? + //[ 0 ] - new message flag + //[ 1-4 ] - id + //[ 5 ] - length + //[ 6-13 ] - data + ////////////////////////////////////////////////////// + + + uint8_t rx_status = read_rx_status(); + + //PĹ™eÄŤtenĂ RX_BUFF_0, pokud je plnĂ˝ + if (bit_is_set(rx_status,6)) //Zprava v bufferu 0 + { + spi.select(true); + spi.write_data(SPI_READ_RX_BUFF_0); + + buffer_1[0] = 1; + + for (uint8_t i=1;i<14;i++) + { + buffer_1[i] = spi.write_and_read_data(0xff); + } + + spi.select(false); + } + + //PĹ™eÄŤtenĂ RX_BUFF_2, pokud je plnĂ˝ + if (bit_is_set(rx_status,7)) //Zprava v bufferu 1 + { + spi.select(true); + spi.write_data(SPI_READ_RX_BUFF_2); + + buffer_2[0] = 1; + + for (uint8_t i=1;i<14;i++) + { + buffer_2[i] = spi.write_and_read_data(0xff); + } + + spi.select(false); + } + + //VytvoĹ™enĂ a uloĹľenĂ can_message + if (buffer_1[0]) + { + can_message message; + + message.id = 0; + message.id |= buffer_1[1]<<3; + message.id |= buffer_1[2]>>5; + message.lenght = buffer_1[5]; + + for(uint8_t i=0; i<message.lenght; i++) + { + message.data[i] = buffer_1[6+i]; + } + + rx_buffer.add(message); + } + + if (buffer_2[0]) + { + can_message message; + message.id = (uint16_t)(buffer_2[1]<<8) | (uint16_t)(buffer_2[2]>>5); + message.lenght = buffer_2[5]; + for(uint8_t i=0; i<message.lenght; i++) + { + message.data[i] = buffer_2[i]; + } + + rx_buffer.add(message); + } +} + +void MCP2515::tx_handler(fifo<can_message> &tx_buffer) +{ + //TODO: buffer priority + + while (tx_buffer.check()) + { + uint8_t reg_sidh, reg_sidl, reg_dlc, reg_data, reg_rts; + + //VybránĂ odesĂlacĂho bufferu + if ( !(read_register(TXB2CTRL) & (1<<TXREQ)) ) + { + reg_sidh = TXB2SIDH; + reg_sidl = TXB2SIDL; + reg_dlc = TXB2DLC; + reg_data = TXB2D0; + reg_rts = SPI_RTS_TXB2; + } + + else if ( !(read_register(TXB1CTRL) & (1<<TXREQ)) ) + { + reg_sidh = TXB1SIDH; + reg_sidl = TXB1SIDL; + reg_dlc = TXB1DLC; + reg_data = TXB1D0; + reg_rts = SPI_RTS_TXB1; + } + + else if ( !(read_register(TXB2CTRL) & (1<<TXREQ)) ) + { + reg_sidh = TXB0SIDH; + reg_sidl = TXB0SIDL; + reg_dlc = TXB0DLC; + reg_data = TXB0D0; + reg_rts = SPI_RTS_TXB0; + } + + else + { + return; //TODO: Tady by to mohlo nÄ›co dÄ›lat, teoreticky uĹľ nemusĂ (pĹ™emĂstÄ›nĂ message) + } + + can_message message = tx_buffer.read(); //TODO: dynamic alocation + + //ZapsánĂ ID + write_register(reg_sidh, (uint8_t) (message.id>>3)); + write_register(reg_sidl, (uint8_t) (message.id<<5)); + + //ZapsánĂ dĂ©lky zprávy + write_register(reg_dlc, message.lenght); + + //ZapsánĂ dat + for (uint8_t i=0; i<message.lenght; i++) + { + write_register(reg_data+i, message.data[i]); + } + + //OdeslánĂ na sbÄ›rnici + spi.select(true); + + spi.write_data(reg_rts); + + spi.select(false); + } +} diff --git a/SW/libs/src/MCP2515.h b/SW/libs/src/MCP2515.h new file mode 100644 index 0000000000000000000000000000000000000000..382b0ce74aff372b23ed2718f06fdf67c04cc515 --- /dev/null +++ b/SW/libs/src/MCP2515.h @@ -0,0 +1,370 @@ +#pragma once + +#include <avr/io.h> +#include <stdint.h> +#include "spi.h" +#include "fifo.h" + +struct can_message +{ + uint16_t id; + uint8_t lenght; + uint8_t data[8]; +}; + +class MCP2515 +{ + //Definice + public: + enum spi_instructions + { + SPI_RESET = 0xC0, + SPI_READ = 0x03, + SPI_READ_RX_BUFF_0 = 0x90, + SPI_READ_RX_BUFF_1 = 0x92, + SPI_READ_RX_BUFF_2 = 0x94, + SPI_READ_RX_BUFF_3 = 0x96, + SPI_WRITE = 0x02, + SPI_LOAD_TX_BUFF_0 = 0x40, + SPI_LOAD_TX_BUFF_1 = 0x41, + SPI_LOAD_TX_BUFF_2 = 0x42, + SPI_LOAD_TX_BUFF_3 = 0x43, + SPI_LOAD_TX_BUFF_4 = 0x44, + SPI_LOAD_TX_BUFF_5 = 0x45, + SPI_RTS_TXB0 = 0x81, + SPI_RTS_TXB1 = 0x82, + SPI_RTS_TXB2 = 0x84, + SPI_READ_STATUS = 0xA0, + SPI_RX_STATUS = 0xB0, + SPI_BIT_MODIFY = 0x05 + }; + + enum can_control_registers + { + RXF0SIDH = 0x00, + RXF0SIDL = 0x01, + RXF0EID8 = 0x02, + RXF0EID0 = 0x03, + RXF1SIDH = 0x04, + RXF1SIDL = 0x05, + RXF1EID8 = 0x06, + RXF1EID0 = 0x07, + RXF2SIDH = 0x08, + RXF2SIDL = 0x09, + RXF2EID8 = 0x0A, + RXF2EID0 = 0x0B, + BFPCTRL = 0x0C, + TXRTSCTRL = 0x0D, + CANSTAT = 0x0E, + CANCTRL = 0x0F, + + RXF3SIDH = 0x10, + RXF3SIDL = 0x11, + RXF3EID8 = 0x12, + RXF3EID0 = 0x13, + RXF4SIDH = 0x14, + RXF4SIDL = 0x15, + RXF4EID8 = 0x16, + RXF4EID0 = 0x17, + RXF5SIDH = 0x18, + RXF5SIDL = 0x19, + RXF5EID8 = 0x1A, + RXF5EID0 = 0x1B, + TEC = 0x1C, + REC = 0x1D, + + RXM0SIDH = 0x20, + RXM0SIDL = 0x21, + RXM0EID8 = 0x22, + RXM0EID0 = 0x23, + RXM1SIDH = 0x24, + RXM1SIDL = 0x25, + RXM1EID8 = 0x26, + RXM1EID0 = 0x27, + CNF3 = 0x28, + CNF2 = 0x29, + CNF1 = 0x2A, + CANINTE = 0x2B, + CANINTF = 0x2C, + EFLG = 0x2D, + + TXB0CTRL = 0x30, + TXB0SIDH = 0x31, + TXB0SIDL = 0x32, + TXB0EID8 = 0x33, + TXB0EID0 = 0x34, + TXB0DLC = 0x35, + TXB0D0 = 0x36, + TXB0D1 = 0x37, + TXB0D2 = 0x38, + TXB0D3 = 0x39, + TXB0D4 = 0x3A, + TXB0D5 = 0x3B, + TXB0D6 = 0x3C, + TXB0D7 = 0x3D, + + TXB1CTRL = 0x40, + TXB1SIDH = 0x41, + TXB1SIDL = 0x42, + TXB1EID8 = 0x43, + TXB1EID0 = 0x44, + TXB1DLC = 0x45, + TXB1D0 = 0x46, + TXB1D1 = 0x47, + TXB1D2 = 0x48, + TXB1D3 = 0x49, + TXB1D4 = 0x4A, + TXB1D5 = 0x4B, + TXB1D6 = 0x4C, + TXB1D7 = 0x4D, + + TXB2CTRL = 0x50, + TXB2SIDH = 0x51, + TXB2SIDL = 0x52, + TXB2EID8 = 0x53, + TXB2EID0 = 0x54, + TXB2DLC = 0x55, + TXB2D0 = 0x56, + TXB2D1 = 0x57, + TXB2D2 = 0x58, + TXB2D3 = 0x59, + TXB2D4 = 0x5A, + TXB2D5 = 0x5B, + TXB2D6 = 0x5C, + TXB2D7 = 0x5D, + + RXB0CTRL = 0x60, + RXB0SIDH = 0x61, + RXB0SIDL = 0x62, + RXB0EID8 = 0x63, + RXB0EID0 = 0x64, + RXB0DLC = 0x65, + RXB0D0 = 0x66, + RXB0D1 = 0x67, + RXB0D2 = 0x68, + RXB0D3 = 0x69, + RXB0D4 = 0x6A, + RXB0D5 = 0x6B, + RXB0D6 = 0x6C, + RXB0D7 = 0x6D, + + RXB1CTRL = 0x70, + RXB1SIDH = 0x71, + RXB1SIDL = 0x72, + RXB1EID8 = 0x73, + RXB1EID0 = 0x74, + RXB1DLC = 0x75, + RXB1D0 = 0x76, + RXB1D1 = 0x77, + RXB1D2 = 0x78, + RXB1D3 = 0x79, + RXB1D4 = 0x7A, + RXB1D5 = 0x7B, + RXB1D6 = 0x7C, + RXB1D7 = 0x7D + }; + + enum control_register_bits + { + //Registr BFPCTRL + B1BFS = 5, + B0BFS = 4, + B1BFE = 3, + B0BFE = 2, + B1BFM = 1, + B0BFM = 0, + + //Registr TXRTSCTRL + B2RTS = 5, + B1RTS = 4, + B0RTS = 3, + B2RTSM = 2, + B1RTSM = 1, + B0RTSM = 0, + + //Registr CANSTAT + OPMOD2 = 7, + OPMOD1 = 6, + OPMOD0 = 5, + ICOD2 = 3, + ICOD1 = 2, + ICOD0 = 1, + + //Registr CANCTRL + REQOP2 = 7, + REQOP1 = 6, + REQOP0 = 5, + ABAT = 4, + CLKEN = 2, + CLKPRE1 = 1, + CLKPRE0 = 0, + + //Registr CNF3 + WAKFIL = 6, + PHSEG22 = 2, + PHSEG21 = 1, + PHSEG20 = 0, + + //Registr CNF2 + BTLMODE = 7, + SAM = 6, + PHSEG12 = 5, + PHSEG11 = 4, + PHSEG10 = 3, + PHSEG2 = 2, + PHSEG1 = 1, + PHSEG0 = 0, + + //Registr CNF1 + SJW1 = 7, + SJW0 = 6, + BRP5 = 5, + BRP4 = 4, + BRP3 = 3, + BRP2 = 2, + BRP1 = 1, + BRP0 = 0, + + //Registr CANINTE + MERRE = 7, + WAKIE = 6, + ERRIE = 5, + TX2IE = 4, + TX1IE = 3, + TX0IE = 2, + RX1IE = 1, + RX0IE = 0, + + //Registr CANINTF + MERRF = 7, + WAKIF = 6, + ERRIF = 5, + TX2IF = 4, + TX1IF = 3, + TX0IF = 2, + RX1IF = 1, + RX0IF = 0, + + //Registr EFLG + RX1OVR = 7, + RX0OVR = 6, + TXB0 = 5, + TXEP = 4, + RXEP = 3, + TXWAR = 2, + RXWAR = 1, + EWARN = 0, + + //Registry TXB0CTRL - TXB2CTRL + ABTF = 6, + MLOA = 5, + TXERR = 4, + TXREQ = 3, + TXP1 = 1, + TXP0 = 0, + + //Registry RXB0CTRL, RXB1CTRL + RXM1 = 6, + RXM0 = 5, + RXRTR = 3, + BUKT = 2, + BUKT1 = 1, + FILHIT0 = 0, + + //Registr TXBnSIDL (n = 0, 1) + EXIDE = 3, + + //Registr RXB1CTRL + FILHIT2 = 2, + FILHIT1 = 1, + + //Registr RXBnSIDL (n = 0, 1) + SRR = 4, + IDE = 3, + + //Registr RXBnDLC (n = 0, 1) + RTR = 6, + DLC3 = 3, + DLC2 = 2, + DLC1 = 1, + DLC0 = 0 + }; + + enum operating_modes + { + CONFIGURATION_MODE, + NORMAL_MODE, + SLEEP_MODE, + LISTEN_ONLY_MODE, + LOOPBACK_MODE + }; + + enum interrupt_modes + { + NONE = 0, + MESSAGE_ERROR_INTERRUPT = (1<<MERRE), + BUS_ACTIVITY_WAKEUP_INTERRUPT = (1<<WAKIE), + ERROR_INTERRUPT = (1<<ERRIE), + TX2_INTERRUPT = (1<<TX2IE), + TX1_INTERRUPT = (1<<TX1IE), + TX0_INTERRUPT = (1<<TX0IE), + RX1_INTERRUPT = (1<<RX1IE), + RX0_INTERRUPT = (1<<RX0IE) + }; + + enum RXnBF_modes + { + DISABLED, + RX_BUFFER_FULL_IRQ, + DIGITAL_OUTPUT, + ON, + OFF + }; + + enum CLKOUT_modes + { + PRESCALER_1, + PRESCALER_2, + PRESCALER_4, + PRESCALER_8, + CLKOUT_ENABLE, + CLKOUT_DISABLE + }; + + private: + spi_class &spi; + + //functions + public: + //Konstruktor, destruktor + MCP2515(spi_class &spi); + ~MCP2515(); + + //Inicializace + void set_baudrate(uint8_t CNF1_val, uint8_t CNF2_val, uint8_t CNF3_val); + void set_interrupt(uint8_t irq_type) { write_register(CANINTE, irq_type); }; + void set_RX0BF_pin(uint8_t mode); + void set_RX1BF_pin(uint8_t mode); + void set_CLKOUT_pin(uint8_t state, uint8_t prescaler = PRESCALER_8); + void set_operating_mode(uint8_t mode); + + //Obsluha + void write_register(uint8_t adress, uint8_t data); + uint8_t read_register(uint8_t adress); + void modify_bit(uint8_t adress, uint8_t mask, uint8_t data); + + uint8_t read_status(uint8_t type); + uint8_t read_rx_status(void); + + void reset(void); + + void can_rx_message(); + void can_tx_message(); + void rx_handler(fifo<can_message> &rx_buffer); + void tx_handler(fifo<can_message> &tx_buffer); + + private: + void spi_ini(void); + +}; //MCP2515 + diff --git a/SW/libs/src/MFRC522.cpp b/SW/libs/src/MFRC522.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a864079f10027199cefff137304cbd57cbfa4f67 --- /dev/null +++ b/SW/libs/src/MFRC522.cpp @@ -0,0 +1,1054 @@ + +#include "MFRC522.h" +#include "spi.h" +#include <avr/io.h> +#include <stdint.h> +#include <stddef.h> +#include <string.h> + +#ifdef PC7 +spi_select_class spi_mfrc522(&DDRC, &PORTC, PC7); + +// Konstruktory +MFRC522_class::MFRC522_class(spi_class &spi): spi(spi) +{ + /* + //Inicializace reset pinu + DDRB |= (1<<PB0); + PORTB |= (1<<PB0); + */ +} //MFRC522_class() + +MFRC522_class::MFRC522_class(spi_class &spi, uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin): spi(spi) +{ + ;; //TODO all there +} //MFRC522_class(uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin) + +// Destruktor +MFRC522_class::~MFRC522_class() +{ +} //~MFRC522_class + + + +///////////////////////////////////////////////////////////////////////////////////// +// Zakladni interface pro komunikaci s MFRC522 +///////////////////////////////////////////////////////////////////////////////////// + + +//Zapise bajt do registru +void MFRC522_class::reader_write_register(uint8_t _register, uint8_t _value) +{ + //Vybrani MFRC522 + spi_mfrc522.select(true); + + spi.write_data(_register & 0x7E); + spi.write_data(_value); + + spi_mfrc522.select(false); +} //void reader_write_register(uint8_t _register, uint8_t _value) + + +//Zapise vybrany pocet bajtu z pole do registru +void MFRC522_class::reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values) +{ + spi_mfrc522.select(true); + + spi.write_data(_register & 0x7E); + for (uint8_t index = 0; index < _count; index++) + { + spi.write_data(_values[index]); + } + + spi_mfrc522.select(false); +} //void reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values) + + +//Precte bajt z registru +uint8_t MFRC522_class::reader_read_register(uint8_t _register) +{ + uint8_t return_value; + + spi_mfrc522.select(true); + + spi.write_data( 0x80 | (_register & 0x7E) ); + return_value = spi.write_and_read_data(0); + + spi_mfrc522.select(false); + + return return_value; +} //uint8_t reader_read_register(uint8_t _register) + + +//Precte zadny pocet bajtu z registru do pole +void MFRC522_class::reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align /* = 0 */) +{ + if (!_count) return; + + uint8_t addres = 0x80 | (_register & 0x7E); + uint8_t index = 0; + + spi_mfrc522.select(true); + + _count--; + + spi.write_data(addres); + + while (index < _count) + { + if ((index == 0) && (_rx_align)) + { + uint8_t mask = 0; + + for (uint8_t i = _rx_align; i <= 7; i++) + { + mask |= (1<<i); + } + + uint8_t r_value = spi.write_and_read_data(addres); + + _values[0] = (_values[index] & ~mask) | (r_value & mask); + } + + else + { + _values[index] = spi.write_and_read_data(addres); + } + + index++; + } + + _values[index] = spi.write_and_read_data(0); + + spi_mfrc522.select(false); +} //void reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align /* = 0 */) + + +//Nastavi bity dane maskou na registr _register +void MFRC522_class::reader_set_register_bit_mask(uint8_t _register, uint8_t _mask) +{ + uint8_t temp; + + temp = reader_read_register(_register); + reader_write_register(_register, (temp | _mask)); +} //void reader_set_register_bit_mask(uint8_t _register, uint8_t _mask) + + +//Zrusi bity dane maskou na registru _register +void MFRC522_class::reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask) +{ + uint8_t temp; + + temp = reader_read_register(_register); + reader_write_register(_register, (temp & (~_mask))); +} //void reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask) + + +//Vypocet crc na koprocesoru MFRC522 +//@return STATUS_OK pri uspechu, nebo STATUS_TIMEOUT +uint8_t MFRC522_class::reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result) +{ + reader_write_register(CommandReg, READER_Idle); //Zastavi ostatni vykonavane prikazy + + reader_write_register(DivIrqReg, 0x04); //Zrusi preruseni od CRCIRq + reader_set_register_bit_mask(FIFOLevelReg, 0x80); //Inicializace FIFO + reader_write_register(FIFODataReg, _lenght, _data); //Odesle data do FIFO + reader_write_register(CommandReg, READER_CalcCRC); //Zacne pocitani CRC + + //Cekani na dokonceni vypoctu + + uint16_t i = 5000; + uint8_t n; + + while (1) + { + n = reader_read_register(DivIrqReg); + + if (n & 0x04) break; //POCITANI CRC HOTOVO + if (--i == 0) return STATUS_TIMEOUT; //Vyprsel timeout + } + + reader_write_register(CommandReg, READER_Idle); + + //Precteni spocitaneho CRC + _result[0] = reader_read_register(CRCResultRegL); + _result[1] = reader_read_register(CRCResultRegH); + + return STATUS_OK; +} //uint8_t reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result) + + + +///////////////////////////////////////////////////////////////////////////////////// +// Metody pro obsluhu MFRC522 +///////////////////////////////////////////////////////////////////////////////////// + + +//Inicializace MFRC522 +void MFRC522_class::reader_ini(void) +{ + DDRC |= (1<<PC6); + PORTC |= (1<<PC6); + //PORTB |= (1<<PB0); //Power on & hard reset + wait_ms(50); + reader_reset(); //Soft reset + + //Nastaveni timeru MFRC522 pro potreby hlidani timeoutu + //Frevence timeru = (13,56 MHz / (2*TPreScaler+1) + //TPreScaler = [TPrescaler_Hi:TPrescaler_Lo] + //TPrescaler_Hi jsou spodni 4 bity v TModeReg + //TPrescaler_Lo je TPrescalerReg + reader_write_register(TModeReg, 0x80); //TAuto=1; Timer zacne automaticky pocitat po dokonceni vysilani + reader_write_register(TPrescalerReg, 0xA9); //Frekvence 40kHz, perioda 25ďż˝s + reader_write_register(TReloadRegH, 0x03); //Reload timer 25ms pred timeoutem + reader_write_register(TReloadRegL, 0xE8); + + reader_write_register(TxASKReg, 0x40); + reader_write_register(ModeReg, 0x3D); + + reader_set_antena_gain(GAIN_43dB); //Nastaveni zisku anteny + + reader_antena_on(); +} //void reader_ini(void) + + +//Vykonani soft resetu +void MFRC522_class::reader_reset(void) +{ + reader_write_register(CommandReg, READER_SoftReset); //Vykona soft reset + + wait_ms(50); //Radsi + + while (reader_read_register(CommandReg) & (1<<4)) + { + ;; + } +} //void reader_reset(void) + + +//Zapne antenu, zapnuti pinu TX1 a TX2 (po resetu jsou vypnute) +void MFRC522_class::reader_antena_on(void) +{ + uint8_t _value = reader_read_register(TxControlReg); + + if ((_value & 0x03) != 0x03) + { + reader_write_register(TxControlReg, (_value | 0x03)); + } +} //void reader_antena_on(void) + + +//Nastaveni gainu anteny +void MFRC522_class::reader_set_antena_gain(uint8_t _gain) +{ + reader_write_register(RFCfgReg, _gain); //Nastaveni zisku anteny +} //void reader_set_antena_gain(_gain) + + +///////////////////////////////////////////////////////////////////////////////////// +// Metody pro komunikaci s rfid kartami +///////////////////////////////////////////////////////////////////////////////////// + + +//Odesle data na kartu a prijme odpoved +//CRC se zvaliduje jen v pripade specifikovani _back_data, _back_lenght +//@return STATUS_OK, +uint8_t MFRC522_class::reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */) +{ + uint8_t wait_irq = 0x30; //RxIRq and IdleIRq + + return reader_communicate_with_card(READER_Transceive, wait_irq, _send_data, _send_lenght, _back_data, _back_lenght, _valid_bits, _rx_align, _check_crc); +} //uint8_t reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */) + + +//Odesle data do MCRF522 FIFO, vykona prikaz, pocka na dokonceni a precte data nazpatek z FIFO +//CRC se zvaliduje jen v pripade specifikovani _back_data, _back_lenght +//@return STATUS_OK, STATUS_TIMEOUT, STATUS_false_ROOM, STATUS_COLLISION, STATUS_MIFARE_NACK, STATUS_CRC_WRONG +uint8_t MFRC522_class::reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data /* = NULL */, uint8_t *_back_lenght /* = NULL */, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */) +{ + uint8_t n; + uint8_t _validBits; + uint16_t i; + + //Priprava dat pro BitFramingReg + uint8_t tx_last_bits = _valid_bits ? *_valid_bits : 0; + uint8_t bit_framing = (_rx_align << 4) + tx_last_bits; //RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + + reader_write_register(CommandReg, READER_Idle); //Zrusi vykonavani vsech prikazu + reader_write_register(ComIrqReg, 0x7F); //Vynuluje vsech 7 bitu preruseni + reader_set_register_bit_mask(FIFOLevelReg, 0x80); //inicializace FIFO + reader_write_register(FIFODataReg, _send_lenght, _send_data); //Zapise _send_data do FIFO + reader_write_register(BitFramingReg, bit_framing); //Vyrovnani bitu + reader_write_register(CommandReg, _command); //Odesle a vykona _commad + + if (_command == READER_Transceive) + { + reader_set_register_bit_mask(BitFramingReg, 0x80); //Odesli data z FIFO na kartu + } + + //Cekani na dokonceni prikazu + //1 smycka while trvďż˝ 17.86us (reader_ini()) + i = 2000; + + while (1) + { + n = reader_read_register(ComIrqReg); + if (n & _wait_irq) break; //Preruseni ohlasilo uspech + + if (n & 0x01) return STATUS_TIMEOUT; //Timer interupt - nic nebylo prijato v 25ms + + if (--i == 0) return STATUS_TIMEOUT; //Ukonceni vsech pokusu po 35.7ms + } + + //Zastavit, pokud se vysktla nejaka chyba + uint8_t error_reg_value = reader_read_register(ErrorReg); //ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr + + if (error_reg_value & 0x13) return STATUS_ERROR; //BufferOvfl ParityErr ProtocolErr + + //Pokud chceme prijmout data nazpet + if (_back_data && _back_lenght) + { + n = reader_read_register(FIFOLevelReg); //Pocet bajtu v FIFO + if (n > *_back_lenght) return STATUS_NO_ROOM; //Neni misto na ulozeni dat + + *_back_lenght = n; //Pocet dat k precteni + reader_read_register(FIFODataReg, n, _back_data, _rx_align); //Prijem dat z FIFO + _validBits = reader_read_register(ControlReg) & 0x07; //RxLastBits[2:0] urcuji pocet validnich prijmutych bitu + + if(_valid_bits) *_valid_bits = _validBits; + } + + //Navrat koliznuho stavu + if (error_reg_value & 0x08) return STATUS_COLLISION; + + //Vypocitani CRC kdyz bylo nastavefalse _check_crc = true + if (_back_data && _back_lenght && _check_crc) + { + if (*_back_lenght == 1 && _validBits == 4) return STATUS_MIFARE_NACK; //MIFARE classic NAK neni v poradku + + if (_send_lenght == 2 || _validBits != 0) return STATUS_CRC_WRONG; //Nemame dostatek dat pro vypocet CRC + + uint8_t control_buffer[2]; + + n = reader_calculate_crc(&_back_data[0], *_back_lenght - 2, &control_buffer[0]); + + if (n != STATUS_OK) return n; + + if ( (_back_data[*_back_lenght - 2] != control_buffer[0]) || (_back_data[*_back_lenght - 1] != control_buffer[1]) ) return STATUS_CRC_WRONG; + } + + return STATUS_OK; +} //uint8_t reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data /* = NULL */, uint8_t *_back_lenght /* = NULL */, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */) + + +//Posle pozadavek typu A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. +//Dve karty v dosahu muzou zpďż˝sobovat STATUS_TIMEOUT +//@return STATUS_OK, nebo STATUS_??? pri chybe +uint8_t MFRC522_class::card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size) +{ + return card_REQA_or_WUPA(CARD_CMD_REQA, _buffer_ATQA, _buffer_size); +} //uint8_t card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size) + + +//Posle prikaz na probuzeni karty +//Dve karty v dosahu muzou zpďż˝sobovat STATUS_TIMEOUT +//@return STATUS_OK, nebo STATUS_??? pri chybe +uint8_t MFRC522_class::card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size) +{ + return card_REQA_or_WUPA(CARD_CMD_WUPA, _buffer_ATQA, _buffer_size); +} //uint8_t card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size) + + +//Posle REQA nebo WUPA prikaz +//Dve karty v dosahu muzou zpďż˝sobovat STATUS_TIMEOUT +//@return STATUS_OK, nebo STATUS_??? pri chybe +uint8_t MFRC522_class::card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size) +{ + uint8_t valid_bits, status; + + if (_buffer_ATQA == NULL || *_buffer_size < 2) return STATUS_NO_ROOM; //Potrebujem mit alespon 2 bity na prijem odpovedi + + reader_clear_register_bit_mask(CollReg, 0x80); + valid_bits = 7; + status = reader_transmit_and_read_data(&_command, 1, _buffer_ATQA, _buffer_size, &valid_bits); + + if (status != STATUS_OK) return status; + + if (*_buffer_size != 2 || valid_bits != 0) return STATUS_ERROR; //ATQA musi byt presne 16 bitu + + return STATUS_OK; +} //uint8_t card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size) + + +//Odesle SELECT/ANTICOLLISION prikaz pro vyber defifalsevane karty +//Pred odeslanim musi byt karta v ready rezimu - card_wake_up() +//Ostatni karty se prepfalseu do rezimu IDLE/HALT +/************************************************************************/ +/*The UID size and value of the chosen PICC is returned in *uid along with the SAK. +* +* A PICC UID consists of 4, 7 or 10 bytes. +* Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: +* UID size Number of UID bytes Cascade levels Example of PICC +* ======== =================== ============== =============== +* single 4 1 MIFARE Classic +* double 7 2 MIFARE Ultralight +* triple 10 3 falset currently in use? +* +* @return STATUS_OK on success, STATUS_??? otherwise. +*/ +/************************************************************************/ +uint8_t MFRC522_class::card_select(UID *uid, uint8_t _valid_bits /* = 0 */) +{ + bool uid_complete, select_done, use_cascade_tag; + uint8_t cascade_level = 1, + result, count, index, + uid_index, //Prvni index c uid->uid_data[] pro pouzivany cascade_level + current_level_kfalsewn_bits; //Pocet bitu soucasneho cascade levelu + + uint8_t buffer[9]; //SELECT/ANTICOLLISION prikaz + 2 bajty CRC + uint8_t buffer_used; //Pocet bajtu v buffer[] pro odeslani do FIFO + uint8_t rx_align; //Pozice prvniho prijateho bitu. Pro BitFramingReg + uint8_t tx_last_bits; //Pocet bitu v naposled prijate zprave. Pro BitFramingReg + uint8_t *response_buffer; + uint8_t response_lenght; + + // Description of buffer structure: + // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 + // Byte 1: NVB Number of Valid Bits (in complete command, falset just the UID): High nibble: complete bytes, Low nibble: Extra bits. + // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. + // Byte 3: UID-data + // Byte 4: UID-data + // Byte 5: UID-data + // Byte 6: BCC Block Check Character - XOR of bytes 2-5 + // Byte 7: CRC_A + // Byte 8: CRC_A + // The BCC and CRC_A is only transmitted if we kfalsew all the UID bits of the current Cascade Level. + // + // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) + // UID size Cascade level Byte2 Byte3 Byte4 Byte5 + // ======== ============= ===== ===== ===== ===== + // 4 bytes 1 uid0 uid1 uid2 uid3 + // 7 bytes 1 CT uid0 uid1 uid2 + // 2 uid3 uid4 uid5 uid6 + // 10 bytes 1 CT uid0 uid1 uid2 + // 2 CT uid3 uid4 uid5 + // 3 uid6 uid7 uid8 uid9 + + //Kontrola zdraveho rozumu ;) + if (_valid_bits > 80) return STATUS_INVALID; + + //Priprava MFRC522 + reader_clear_register_bit_mask(CollReg, 0x80); //ValuesAfterColl=1 => Bits received after collision are cleared. + + //Opakovani cascade level smycky do precteni celeho UID + uid_complete = false; + + while (! uid_complete) + { + //Nastaveni cascade level v SEL bajtu, zjisteny potreby pouziti cascade tag ve 2 bajtu + switch (cascade_level) + { + case 1: buffer[0] = CARD_CMD_SEL_CL1; + uid_index = 0; + use_cascade_tag = _valid_bits && uid->size > 4; + break; + + case 2: buffer[0] = CARD_CMD_SEL_CL2; + uid_index = 3; + use_cascade_tag = _valid_bits && uid->size > 7; + break; + + case 3: buffer[0] = CARD_CMD_SEL_CL3; + uid_index = 6; + use_cascade_tag = false; + break; + + default: return STATUS_INTERNAL_ERROR; + break; + } + + //Kolik je UID bitu v tomto cascade levelu + current_level_kfalsewn_bits = _valid_bits - (8 * uid_index); + if (current_level_kfalsewn_bits < 0) current_level_kfalsewn_bits = 0; + + //Zkopirovani znamych uid->uid_data[] do buffer[] + index = 2; + + if (use_cascade_tag) buffer[index++] = CARD_CMD_CT; + + uint8_t bytes_to_copy = current_level_kfalsewn_bits / 8 + (current_level_kfalsewn_bits % 8 ? 1 : 0); + + if (bytes_to_copy) + { + uint8_t max_bytes = use_cascade_tag ? 3 : 4; + + if (bytes_to_copy > max_bytes) bytes_to_copy = max_bytes; + + for (count = 0; count < bytes_to_copy; count++) + { + buffer[index++] = uid->uid_data[uid_index + count]; + } + } + + //falsew that the data has been copied we need to include the 8 bits in CT in currentLevelKfalsewnBits + if (use_cascade_tag) current_level_kfalsewn_bits += 8; + + // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. + select_done = false; + + while (! select_done) + { + //Kolik bitu je potreba odeslat a prijmout + if (current_level_kfalsewn_bits >= 32) //All UID bits in this Cascade Level are kfalsewn. This is a SELECT. + { + buffer[1] = 0x70; //NVB - pocet platnych bitu - 7 + + //Calulate BCC - Block Check Character + buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; + + //Vypocet CRC + result = reader_calculate_crc(buffer, 7, &buffer[7]); + + if (result != STATUS_OK) return result; + + tx_last_bits = 0; //0 => vsech 8 bitu je v poradku + buffer_used = 9; + + //Store response in the last 3 bytes of buffer (BCC and CRC_A - falset needed after tx) + response_buffer = &buffer[6]; + response_lenght = 3; + } + + else //This is an ANTICOLLISION. + { + tx_last_bits = current_level_kfalsewn_bits % 8; + count = current_level_kfalsewn_bits / 8; //Celkovy pocet bajtu UID + index = 2 + count; //Number of whole bytes: SEL + NVB + UIDs + buffer[1] = (index << 4) + tx_last_bits; + buffer_used = index + (tx_last_bits ? 1 : 0); + + //Ulozeni odpovedi v nepouzite casti bufferu + response_buffer = &buffer[index]; + response_lenght = sizeof(buffer) - index; + } + + //Bit adjustments + rx_align = tx_last_bits; //Having a seperate variable is overkill. But it makes the next line easier to read. + reader_write_register(BitFramingReg, (rx_align<<4) + tx_last_bits); //RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + + //Odeslani buffer[] a prijmuti odpovedi + result = reader_transmit_and_read_data(buffer, buffer_used, response_buffer, &response_lenght, &tx_last_bits, rx_align); + + if (result == STATUS_COLLISION) //Vice karet v dosahu = kolize + { + result = reader_read_register(CollReg); + + if (result & 0x20) return STATUS_COLLISION; //Without a valid collision position we canfalset continue + + uint8_t collisionn_position = result & 0x1F; + + if (collisionn_position == 0) collisionn_position = 32; + + if (collisionn_position <= current_level_kfalsewn_bits) return STATUS_INTERNAL_ERROR; //false progress - should falset happen + + //Vybrani karty s nastavenym bitem + current_level_kfalsewn_bits = collisionn_position; + + count = (current_level_kfalsewn_bits - 1) % 8; //Bit pro modifikaci + index = 1 + (current_level_kfalsewn_bits / 8) + (count ? 1 : 0); //Prvni bajt je index 0 + buffer[index] |= (1<<count); + } + + else if (result != STATUS_OK) return result; + + else //STATUS_OK + { + if (current_level_kfalsewn_bits >= 32) select_done = true; //SELECT + + else current_level_kfalsewn_bits = 32; //ANTICOLLISION + //Run loop again to do the SELECT. + } + } //while (! select_done) + + + //We do falset check the CBB - it was constructed by us above. + + //Copy the found UID bytes from buffer[] to uid->uid_data[] + index = (buffer[2] == CARD_CMD_CT) ? 3 : 2; //Zdrojovy index v buffer[] + bytes_to_copy = (buffer[2] == CARD_CMD_CT) ? 3 : 4; + + for (count = 0; count < bytes_to_copy; count++) + { + uid->uid_data[uid_index + count] = buffer[index++]; + } + + //Kontrola odpovedi SAK (Select Ackfalsewledge) + if (response_lenght != 3 || tx_last_bits != 0) return STATUS_ERROR; //SAK je vzdy 24 bitu (1 bajt + CRC) + + //Kontrola CRC, do our own calculation and store the control in buffer[2..3] - those bytes are falset needed anymore. + result = reader_calculate_crc(response_buffer, 1, &buffer[2]); + + if (result != STATUS_OK) return result; + + if ( (buffer[2] != response_buffer[1]) || (buffer[3] != response_buffer[2])) return STATUS_CRC_WRONG; + + if (response_buffer[0] & 0x04) cascade_level++; //Nasteven cascade level, UID jeste neni kompletni + + else + { + uid_complete = true; + uid->sak = response_buffer[0]; + } + } //while (! uid_complete) + + + //Nastaveni spravneho uid->size + uid->size = 3 * cascade_level +1; + + return STATUS_OK; +} // uint8_t card_select(UID *uid, uint8_t _valid_bits /* = 0 */) + + +//Prepne kartu ze stavu active do stavu halt +//@return STATUS_OK, nebo STATUS_??? pro chybu +uint8_t MFRC522_class::card_halt(void) +{ + uint8_t result; + uint8_t buffer[4]; + + //Naplneni buffer[prikazy] + buffer[0] = CARD_CMD_HLTA; + buffer[1] = 0; + + //Vypocet CRC + result = reader_calculate_crc(buffer, 2, &buffer[2]); + + if (result != STATUS_OK) return result; + + //Odeslani prikazu + // The standard says: + // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the + // HLTA command, this response shall be interpreted as 'falset ackfalsewledge'. + // We interpret that this way: Only STATUS_TIMEOUT is an success. + + result = reader_transmit_and_read_data(buffer, sizeof(buffer), NULL, 0); + + if (result == STATUS_TIMEOUT) return STATUS_OK; //falsermalni prubeh + if (result == STATUS_OK) return STATUS_ERROR; //Trocha ironie ;) + + return result; +} //uint8_t card_halt(void) + + + +///////////////////////////////////////////////////////////////////////////////////// +// Metody pro komunikaci s MIFARE kartami +///////////////////////////////////////////////////////////////////////////////////// + + +/** + * Executes the MFRC522 MFAuthent command. + * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. + * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. + * For use with MIFARE Classic PICCs. + * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. + * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise false new communications can start. + * + * All keys are set to FFFFFFFFFFFFh at chip delivery. + * + * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. + */ +uint8_t MFRC522_class::reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid) +{ + uint8_t wait_irq = 0x10; //IdleIRq + + //Prikazovy buffer + uint8_t send_data[12]; + send_data[0] = _command; + send_data[1] = _block_addr; + + for (uint8_t i = 0; i < MF_KEY_SIZE; i++) + { + send_data[2+i] = key->key_data[i]; + } + + for (uint8_t i = 0; i < 4; i++) + { + send_data[8+i] = uid->uid_data[i]; + } + + //Start authentifikace + + return reader_communicate_with_card(READER_MFAuthent, wait_irq, &send_data[0], sizeof(send_data)); +} //uint8_t reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid) + + +//Ukonci authentifikaci s kartou +//Dokud to neprobehne, neni mozna komunikace s dalsi kartou!! +void MFRC522_class::reader_stop_crypto(void) +{ + reader_clear_register_bit_mask(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] +} //void reader_stop_crypto(void) + + +//Precte 16 bajtu + 2 bajty CRC z aktivni karty +/** + * For MIFARE Classic the sector containing the block must be authenticated before calling this function. + * + * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. + * The MF0ICU1 returns a NAK for higher addresses. + * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. + * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. + * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. + * + * The buffer must be at least 18 bytes because a CRC_A is also returned. + * Checks the CRC_A before returning STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size) +{ + uint8_t result; + + if (_buffer == NULL || *_buffer_size < 18) return STATUS_NO_ROOM; + + //Prikazovy buffer + _buffer[0] = CARD_CMD_MF_READ; + _buffer[1] = _block_addr; + + //Vypocet CRC + result = reader_calculate_crc(_buffer, 2, &_buffer[2]); + + if (result != STATUS_OK) return result; + + //Odeslani _buffer[], prijmuti odpovedi a kontrola CRC + return reader_transmit_and_read_data(_buffer, 4, _buffer, _buffer_size, NULL, 0, true); +} //uint8_t mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size) + + +//Zapise 16 bajtu na aktivni kartu +/** + * For MIFARE Classic the sector containing the block must be authenticated before calling this function. + * + * For MIFARE Ultralight the opretaion is called "COMPATIBILITY WRITE". + * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) + * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. + * * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size) +{ + uint8_t result; + + if (_buffer == NULL || _buffer_size < 16) return STATUS_INVALID; + + // Mifare Classic protocol requires two communications to perform a write. + // Step 1: Tell the PICC we want to write to block blockAddr. + uint8_t cmd_buffer[2]; + cmd_buffer[0] = CARD_CMD_MF_WRITE; + cmd_buffer[1] = _block_addr; + + result = reader_mifare_transmit_and_receive(cmd_buffer, 2); //Adds CRC_A and checks that the response is MF_ACK. + + if (result != STATUS_OK) return result; + + // Step 2: Transfer the data + result = reader_mifare_transmit_and_receive(_buffer, _buffer_size); //Adds CRC_A and checks that the response is MF_ACK. + + if (result != STATUS_OK) return result; + + return STATUS_OK; +} //uint8_t mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size) + + +//Zapise 4 bajty do aktivni MIFARE Ultaluight karty +//@return STATUS_OK, nebo STATUS_??? pro chybu +uint8_t MFRC522_class::mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size) +{ + uint8_t result; + + if (_buffer == NULL ||_buffer_size < 4) return STATUS_INVALID; + + //Prikazovy buffer + uint8_t cmd_buffer[6]; + cmd_buffer[0] = CARD_CMD_UL_WRITE; + cmd_buffer[1] = _page; + + memcpy(&cmd_buffer[2], _buffer, 4); + + //Zapsat data + result = reader_mifare_transmit_and_receive(cmd_buffer, 6); //Adds CRC_A and checks that the response is MF_ACK. + + if (result != STATUS_OK) return result; + + return STATUS_OK; +} //uint8_t mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size) + + +/** + * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_decrement(uint8_t _block_addr, long _delta) +{ + return mifare_two_step_helper(CARD_CMD_MF_DECREMENT, _block_addr, _delta); +} //uint8_t mifare_decrement(uint8_t _block_addr, long _delta) + + +/** + * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_increment(uint8_t _block_addr, long _delta) +{ + return mifare_two_step_helper(CARD_CMD_MF_INCREMENT, _block_addr, _delta); +} //uint8_t mifare_increment(uint8_t _block_addr, long _delta) + + +/** + * MIFARE Restore copies the value of the addressed block into a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_restore(uint8_t _block_addr) +{ + // The datasheet describes Restore as a two step operation, but does falset explain what data to transfer in step 2. + // Doing only a single step does falset work, so I chose to transfer 0L in step two. + + return mifare_two_step_helper(CARD_CMD_MF_RESTORE, _block_addr, 0L); +} //uint8_t mifare_restore(uint8_t _block_addr) + + +/** + * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data) +{ + uint8_t result; + uint8_t cmd_buffer[2]; + + //Step 1: Tell the PICC the command and block address + cmd_buffer[0] = _command; + cmd_buffer[1] = _block_addr; + + result = reader_mifare_transmit_and_receive(cmd_buffer, 2); //Adds CRC_A and checks that the response is MF_ACK. + + if (result != STATUS_OK) return result; + + //Step 2: Transfer the data + result = reader_mifare_transmit_and_receive((uint8_t *)&_data, 4, true); //Adds CRC_A and accept timeout as success. + + if (result != STATUS_OK) return result; + + return STATUS_OK; +} //uint8_t mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data) + + +/** + * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::mifare_transfer(uint8_t _block_addr) +{ + uint8_t result; + uint8_t cmd_buffer[2]; + + //Tell the PICC we want to transfer the result into block blockAddr. + cmd_buffer[0] = CARD_CMD_MF_TRANSFER; + cmd_buffer[1] = _block_addr; + + result = reader_mifare_transmit_and_receive(cmd_buffer, 2); //Adds CRC_A and checks that the response is MF_ACK.Adds CRC_A and checks that the response is MF_ACK. + + if (result != STATUS_OK) return result; + + return result; +} //uint8_t mifare_transfer(uint8_t _block_addr) + + + +///////////////////////////////////////////////////////////////////////////////////// +// Podpurne funkce +///////////////////////////////////////////////////////////////////////////////////// + + +/** + * Wrapper for MIFARE protocol communication. + * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ +uint8_t MFRC522_class::reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout /* = false */) +{ + uint8_t result; + uint8_t cmd_buffer[18]; //16 bajtu data, 2 bajty CRC + + if (_send_data == NULL || _send_lenght > 16) return STATUS_INVALID; + + // Copy sendData[] to cmdBuffer[] and add CRC_A + memcpy(cmd_buffer, _send_data, _send_lenght); + + result = reader_calculate_crc(cmd_buffer, _send_lenght, &cmd_buffer[_send_lenght]); + + if (result != STATUS_OK) return result; + + _send_lenght += 2; + + //Transceive the data, store the reply in cmdBuffer[] + uint8_t wait_irq = 0x30; //RxIRq and IdleIRq + uint8_t cmd_buffer_size = sizeof(cmd_buffer); + uint8_t valid_bits = 0; + + result = reader_communicate_with_card(READER_Transceive, wait_irq, cmd_buffer, _send_lenght, cmd_buffer, &cmd_buffer_size, &valid_bits); + + if (_accept_timeout && result == STATUS_TIMEOUT) return STATUS_OK; + + if (result != STATUS_OK) return result; + + //The PICC must reply with a 4 bit ACK + if (cmd_buffer_size != 1 || valid_bits != 4) return STATUS_ERROR; + + if (cmd_buffer[0] != MF_ACK) return STATUS_MIFARE_NACK; + + return STATUS_OK; +} //uint8_t reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout /* = false */) + + +//Returns a string pointer to a status code name. +const char *MFRC522_class::get_status_code_name(uint8_t _code) +{ + switch (_code) + { + case STATUS_OK: return "Success."; break; + case STATUS_ERROR: return "Error in communication."; break; + case STATUS_COLLISION: return "Collission detected."; break; + case STATUS_TIMEOUT: return "Timeout in communication."; break; + case STATUS_NO_ROOM: return "A buffer is falset big efalseugh."; break; + case STATUS_INTERNAL_ERROR: return "Internal error in the code. Should falset happen."; break; + case STATUS_INVALID: return "Invalid argument."; break; + case STATUS_CRC_WRONG: return "The CRC_A does falset match."; break; + case STATUS_MIFARE_NACK: return "A MIFARE CARD responded with NAK."; break; + default: return "Unkfalsewn error"; break; + } +} //const char *get_status_code_name(uint8_t _code) + + +//Translates the SAK (Select Ackfalsewledge) to a PICC type. +// @return PICC_Type +uint8_t MFRC522_class::card_get_type(uint8_t _sak) +{ + if (_sak & 0x04) //UID falset complete + { + return CARD_TYPE_NOT_COMPLETE; + } + + switch (_sak) + { + case 0x09: return CARD_TYPE_MIFARE_MINI; break; + case 0x08: return CARD_TYPE_MIFARE_1K; break; + case 0x18: return CARD_TYPE_MIFARE_4K; break; + case 0x00: return CARD_TYPE_MIFARE_UL; break; + case 0x10: + case 0x11: return CARD_TYPE_MIFARE_PLUS; break; + case 0x01: return CARD_TYPE_TNP3XXX; break; + default: break; + } + + if (_sak & 0x20) + { + return CARD_TYPE_ISO_14443_4; + } + + if (_sak & 0x40) + { + return CARD_TYPE_ISO_18092; + } + + return CARD_TYPE_UNKNOWN; +} //uint8_t card_get_type(uint8_t _sak) + + +//Returns a string pointer to the PICC type name. +const char *MFRC522_class::card_get_type_name(uint8_t _type) +{ + switch (_type) + { + case CARD_TYPE_ISO_14443_4: return "CARD compliant with ISO/IEC 14443-4"; break; + case CARD_TYPE_ISO_18092: return "CARD compliant with ISO/IEC 18092 (NFC)"; break; + case CARD_TYPE_MIFARE_MINI: return "MIFARE Mini, 320 bytes"; break; + case CARD_TYPE_MIFARE_1K: return "MIFARE 1KB"; break; + case CARD_TYPE_MIFARE_4K: return "MIFARE 4KB"; break; + case CARD_TYPE_MIFARE_UL: return "MIFARE Ultralight or Ultralight C"; break; + case CARD_TYPE_MIFARE_PLUS: return "MIFARE Plus"; break; + case CARD_TYPE_TNP3XXX: return "MIFARE TNP3XXX"; break; + case CARD_TYPE_NOT_COMPLETE: return "SAK indicates UID is falset complete."; break; + case CARD_TYPE_UNKNOWN: + default: return "Unkfalsewn type"; break; + } +} //const char *card_get_type_name(uint8_t _type) + + +//Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). +void MFRC522_class::mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3) +{ + uint8_t c1 = ((_g3 & 4) << 1) | ((_g2 & 4) << 0) | ((_g1 & 4) >> 1) | ((_g0 & 4) >> 2); + uint8_t c2 = ((_g3 & 2) << 2) | ((_g2 & 2) << 1) | ((_g1 & 2) << 0) | ((_g0 & 2) >> 1); + uint8_t c3 = ((_g3 & 1) << 3) | ((_g2 & 1) << 2) | ((_g1 & 1) << 1) | ((_g0 & 1) << 0); + + _acces_bit_buffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); + _acces_bit_buffer[1] = c1 << 4 | (~c3 & 0xF); + _acces_bit_buffer[2] = c3 << 4 | c2; +} //void mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3) + + + +///////////////////////////////////////////////////////////////////////////////////// +// Uzitecne metody +///////////////////////////////////////////////////////////////////////////////////// + + +//Byla detekovana karta? (odpoved na CARD_CMD_REQA) +//true/false +bool MFRC522_class::card_is_new_present(void) +{ + uint8_t buffer_ATQA[2]; + uint8_t buffer_size = sizeof(buffer_ATQA); + + uint8_t result = card_request(buffer_ATQA, &buffer_size); + + return (result == STATUS_OK || result == STATUS_COLLISION); +} //bool card_is_new_present(void) + + +/** + * Simple wrapper around PICC_Select. + * Returns true if a UID could be read. + * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. + * The read UID is available in the class variable uid. + * + * @return bool + */ +bool MFRC522_class::card_read_serial(void) +{ + uint8_t result = card_select(&uid); + + return (result == STATUS_OK); +} //bool card_read_serial(void) +#endif + +//(c) Martin Vitek 2013 (OK1KVK) diff --git a/SW/libs/src/MFRC522.h b/SW/libs/src/MFRC522.h new file mode 100644 index 0000000000000000000000000000000000000000..473fe99004cece0c7dc007dd4419b9dfbded0580 --- /dev/null +++ b/SW/libs/src/MFRC522.h @@ -0,0 +1,317 @@ +#pragma once + +//TODO: Popis MFRC522, jednotlivych rfid karet a pouziti + +//Knihovna vyuziva SPI komunikaci + +//reader - PCD (Proximity Coupling Device) +//card - PICC (Proximity Integrated Circuit Card) + +#include <avr/io.h> +#include <stdint.h> +#include <stddef.h> +#include <string.h> + + +#include "spi.h" +#include "wait.h" + + + +class MFRC522_class +{ + //Definice + public: + + //MFRC522 registry + //Vsechny adresy jsou posunuty o 1 bit vlevo (datasheet 8.1.2.3) + enum reader_register + { + // Page 0: Command and status + // 0x00 // reserved for future use + CommandReg = 0x01 << 1, // starts and stops command execution + ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits + DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits + ComIrqReg = 0x04 << 1, // interrupt request bits + DivIrqReg = 0x05 << 1, // interrupt request bits + ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed + Status1Reg = 0x07 << 1, // communication status bits + Status2Reg = 0x08 << 1, // receiver and transmitter status bits + FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer + FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer + WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning + ControlReg = 0x0C << 1, // miscellaneous control registers + BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames + CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface + // 0x0F // reserved for future use + + // Page 1:Command + // 0x10 // reserved for future use + ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving + TxModeReg = 0x12 << 1, // defines transmission data rate and framing + RxModeReg = 0x13 << 1, // defines reception data rate and framing + TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2 + TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation + TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver + RxSelReg = 0x17 << 1, // selects internal receiver settings + RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder + DemodReg = 0x19 << 1, // defines demodulator settings + // 0x1A // reserved for future use + // 0x1B // reserved for future use + MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters + MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters + // 0x1E // reserved for future use + SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface + + // Page 2: Configuration + // 0x20 // reserved for future use + CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation + CRCResultRegL = 0x22 << 1, + // 0x23 // reserved for future use + ModWidthReg = 0x24 << 1, // controls the ModWidth setting? + // 0x25 // reserved for future use + RFCfgReg = 0x26 << 1, // configures the receiver gain + GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation + CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation + ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation + TModeReg = 0x2A << 1, // defines settings for the internal timer + TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. + TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value + TReloadRegL = 0x2D << 1, + TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value + TCounterValueRegL = 0x2F << 1, + + // Page 3:Test Registers + // 0x30 // reserved for future use + TestSel1Reg = 0x31 << 1, // general test signal configuration + TestSel2Reg = 0x32 << 1, // general test signal configuration + TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7 + TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus + TestBusReg = 0x35 << 1, // shows the status of the internal test bus + AutoTestReg = 0x36 << 1, // controls the digital self test + VersionReg = 0x37 << 1, // shows the software version + AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2 + TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1 + TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2 + TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels + // 0x3C // reserved for production tests + // 0x3D // reserved for production tests + // 0x3E // reserved for production tests + // 0x3F // reserved for production tests + }; + + + //MFRDC522 prikazy + enum reader_command + { + READER_Idle = 0x00, // no action, cancels current command execution + READER_Mem = 0x01, // stores 25 bytes into the internal buffer + READER_GenerateRandomID = 0x02, // generates a 10-byte random ID number + READER_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test + READER_Transmit = 0x04, // transmits data from the FIFO buffer + READER_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit + READER_Receive = 0x08, // activates the receiver circuits + READER_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission + READER_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a READER + READER_SoftReset = 0x0F // resets the MFRC522 + }; + + + //Prikazy pro rfid karty + enum card_command + { + // The commands used by the reader to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) + CARD_CMD_REQA = 0x26, // REQuest command, Type A. Invites CARDs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. + CARD_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites CARDs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + CARD_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. + CARD_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 + CARD_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 1 + CARD_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1 + CARD_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE CARD to go to state HALT. + // The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9) + // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. + // The read/write commands can also be used for MIFARE Ultralight. + CARD_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A + CARD_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B + CARD_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the CARD. Also used for MIFARE Ultralight. + CARD_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the CARD. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. + CARD_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. + CARD_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. + CARD_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. + CARD_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. + // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + // The CARD_CMD_MF_READ and CARD_CMD_MF_WRITE can also be used for MIFARE Ultralight. + CARD_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. + }; + + + //MIFARE konstanty + enum mifare_misc + { + MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. + MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. + }; + + + //Typy karet, ktere umime detekovat (po pridani dalsich je treba updatovat card_get_type_name() ) + enum card_type + { + CARD_TYPE_UNKNOWN = 0, + CARD_TYPE_ISO_14443_4 = 1, // CARD compliant with ISO/IEC 14443-4 + CARD_TYPE_ISO_18092 = 2, // CARD compliant with ISO/IEC 18092 (NFC) + CARD_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes + CARD_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB + CARD_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB + CARD_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C + CARD_TYPE_MIFARE_PLUS = 7, // MIFARE Plus + CARD_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure + CARD_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete. + }; + + + //Navratove hodnoty metod teto tridy (po pridani dalsich se musi updatovat get_status_code_name() ) + enum status_code + { + STATUS_OK = 1, // Success + STATUS_ERROR = 2, // Error in communication + STATUS_COLLISION = 3, // Collission detected + STATUS_TIMEOUT = 4, // Timeout in communication. + STATUS_NO_ROOM = 5, // A buffer is not big enough. + STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-) + STATUS_INVALID = 7, // Invalid argument. + STATUS_CRC_WRONG = 8, // The CRC_A does not match + STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK. + }; + + + //Definice gainu + enum gain_code + { + GAIN_18dB = 0x00, + GAIN_23dB = 0x10, + GAIN_18dB2 = 0x20, + GAIN_23dB2 = 0x30, + GAIN_33dB = 0x40, + GAIN_38dB = 0x50, + GAIN_43dB = 0x60, + GAIN_48dB = 0x70 + }; + + + //Struktura pro ulozeni UID karty + typedef struct + { + uint8_t size; //Velikost UID (4, 7, 10 bajtu) + uint8_t uid_data[10]; + uint8_t sak; //Navratovy kod karty po uspesnem odeslani UID + } UID; + + + //Struktura pro MIFAFE Crypto1 klic + typedef struct + { + uint8_t key_data[MF_KEY_SIZE]; + } mifare_key; + + private: + spi_class &spi; + + //Promene + public: + + //Inicializace UID + UID uid; + + private: + + //Velikost MFRC522 FIFO + static const uint8_t fifo_size = 64; + + //Port a pin resetovaciho pinu MFRC522 + uint8_t reset_port; + uint8_t reset_pin; + + //Port a pin SS pinu MFRC522 + uint8_t select_port; + uint8_t select_pin; + + + //Metody + public: + + //Konstruktor, destruktor + MFRC522_class(spi_class &spi); + MFRC522_class(spi_class &spi, uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin); + ~MFRC522_class(); + + //Zakladni interface pro komunikaci s MFRC522 + void reader_write_register(uint8_t _register, uint8_t _value); + void reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values); + + uint8_t reader_read_register(uint8_t _register); + void reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align = 0); + + void set_bit_mask(uint8_t _register, uint8_t _mask); + + void reader_set_register_bit_mask(uint8_t _register, uint8_t _mask); + void reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask); + + uint8_t reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result); + + + //Metody pro obsluhu MFRC522 + void reader_ini(void); + void reader_reset(void); + void reader_antena_on(void); + void reader_set_antena_gain(uint8_t _gain); + + + //Metody pro komunikaci s rfid kartami + uint8_t reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits = NULL, uint8_t _rx_align = 0, bool _check_crc = false); + uint8_t reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data = NULL, uint8_t *_back_lenght = NULL, uint8_t *_valid_bits = NULL, uint8_t _rx_align = 0, bool _check_crc = false); + + uint8_t card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size); + uint8_t card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size); + uint8_t card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size); + uint8_t card_select(UID *uid, uint8_t _valid_bits = 0); + uint8_t card_halt(void); + + + //Metody pro komunikaci s MIFARE kartami + uint8_t reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid); + void reader_stop_crypto(void); + uint8_t mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size); + uint8_t mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size); + uint8_t mifare_decrement(uint8_t _block_addr, long _delta); + uint8_t mifare_increment(uint8_t _block_addr, long _delta); + uint8_t mifare_restore(uint8_t _block_addr); + uint8_t mifare_transfer(uint8_t _block_addr); + uint8_t mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size); + + + //Podpurne metody + uint8_t reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout = false); + const char *get_status_code_name(uint8_t _code); + uint8_t card_get_type(uint8_t _sak); + const char *card_get_type_name(uint8_t _type); + void mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3); + + + //Uzitecne metody + bool card_is_new_present(void); + bool card_read_serial(void); + + //Odeslani dat na uart + + //Odeslani dat na lcd + + + protected: + private: + uint8_t mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data); + +}; //MFRC522_class + + + +//(c) Martin Vitek 2013 (OK1KVK) diff --git a/SW/libs/src/adc.cpp b/SW/libs/src/adc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2233c2cb7b4e18e9b3bc47e2ce1a6b7d3b1038d6 --- /dev/null +++ b/SW/libs/src/adc.cpp @@ -0,0 +1,129 @@ + +#include "adc.h" +#include <avr/io.h> +#include <stdint.h> + +// default constructor +adc_class::adc_class() +{ +} //adc + +// default destructor +adc_class::~adc_class() +{ +} //~adc + + +////////////////////////////////////////////////////////////////////////// +/////////////////////////////Inicializace///////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void adc_class::set_reference_voltage(reference_voltages reference_voltage) +{ + ADMUX &= ~((1<<REFS1) | (1<<REFS0)); + ADMUX |= reference_voltage; +} //void set_reference_voltage(uint8_t _reference) + +void adc_class::set_result_aligment(result_alignment alignment) +{ + if (alignment == LEFT) ADMUX |= (1<<ADLAR); + else ADMUX &= ~(1<<ADLAR); +} //void set_result_aligment(uint8_t _aligment) + +void adc_class::set_prescaler(prescalers prescaler) +{ + ADCSRA &= ~((1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)); + ADCSRA |= prescaler; +} //void set_prescaler(uint8_t _prescaler) + +void adc_class::enable_free_running_mode() +{ + ADCSRA |= (1<<ADFR); +} //void enable_free_running_mode() + +void adc_class::disable_free_running_mode() +{ + ADCSRA &= ~(1<<ADFR); +} //void disable_free_running_mode() + +void adc_class::enable_adc() +{ + ADCSRA |= (1<<ADEN); +} //void enable_adc() + +void adc_class::enable_adc(bool status) +{ + if (status) ADCSRA |= (1<<ADEN); + else ADCSRA &= ~(1<<ADEN); +} //void enable_adc(bool _status) + +/* +#ifndef __AVR_ATmega8__ +void adc_class::enable_auto_trrigger() +{ + ADCSRA |= (1<<ADATE); +} //void enable_auto_trrigger() + +void adc_class::enable_auto_trrigger(bool _status) +{ + switch (_status) + { + case true: ADCSRA |= (1<<ADATE); + break; + + case false: ADCSRA &= ~(1<<ADATE); + break; + + default: ADCSRA |= (1<<ADATE); + break; + } +} //void enable_auto_trrigger(bool _status) +#endif +*/ + +void adc_class::enable_interrupt() +{ + ADCSRA |= (1<<ADIE); +} //void enable_interrupt() + +void adc_class::enable_interrupt(bool _status) +{ + if (_status) ADCSRA |= (1<<ADIE); + else ADCSRA &= ~(1<<ADIE); +} //void enable_interrupt(bool _status) + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////Obsluha/////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void adc_class::start_conversion() +{ + ADCSRA |= (1<<ADSC); +} //void start_conversion() + +void adc_class::set_channel(channels channel) +{ + ADMUX &= ~((1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0)); + ADMUX |= channel; +} //void set_channel(uint8_t _channel) + +bool adc_class::read_interrupt_flag() +{ + return (bool)(ADCSRA & (1<<ADIF)); +} //uint8_t read_interrupt_flag() + +uint16_t adc_class::read_adc() +{ + start_conversion(); + while (ADCSRA & (1<<ADSC)); + + return ADC; +} //uint16_t read_adc() + +uint16_t adc_class::read_adc(channels channel) +{ + set_channel(channel); + + return read_adc(); +} //uint16_t read_adc(uint8_t _channel) diff --git a/SW/libs/src/adc.h b/SW/libs/src/adc.h new file mode 100644 index 0000000000000000000000000000000000000000..8c2ab632eba2be085881340d12994674ef2d0b9c --- /dev/null +++ b/SW/libs/src/adc.h @@ -0,0 +1,91 @@ +#pragma once + +#include <avr/io.h> +#include <stdint.h> + +//TODO: ATmega16/32 má ADATE: ADC Auto Trigger Enable +#if defined (__AVR_ATmega16__) || (__AVR_ATmega16A__) || (__AVR_ATmega32__) || (__AVR_ATmega32A__) + #define ADFR ADATE +#endif + +#ifndef ADFR + #define ADFR ADATE +#endif + +class adc_class +{ + //Definice + public: + enum reference_voltages + { + AREF, //VnÄ›jšà reference pĹ™ipojená na AREF PIN + AVCC, //VnitĹ™nĂ reference z napájecĂho napÄ›tĂ + INTERNAL_REFERENCE //VnitĹ™nĂ reference 2.56V + }; + + enum result_alignment + { + RIGHT, + LEFT + }; + + enum channels + { + ADC0, + ADC1, + ADC2, + ADC3, + ADC4, + ADC5, + ADC6, + ADC7 + }; + + enum prescalers + { + PRESCALER_2, + PRESCALER_2_2, + PRESCALER_4, + PRESCALER_8, + PRESCALER_16, + PRESCALER_32, + PRESCALER_64, + PRESCALER_128 + }; + + //functions + public: + //Konstruktory, destruktor + adc_class(); + ~adc_class(); + + //Inicializace ADC + void set_reference_voltage(reference_voltages reference_voltage); + void set_result_aligment(result_alignment alignment); + void set_prescaler(prescalers prescaler); + void enable_free_running_mode(); + void disable_free_running_mode(); + + void enable_adc(); + void enable_adc(bool status); + + /* + #ifndef __AVR_ATmega8__ + void enable_auto_trrigger(); + void enable_auto_trrigger(bool _status); + #endif + */ + + void enable_interrupt(); + void enable_interrupt(bool _status); + + //Obsluha + void start_conversion(); + void set_channel(channels channel); + + bool read_interrupt_flag(); + + uint16_t read_adc(); + uint16_t read_adc(channels _channel); +}; //adc_class + diff --git a/SW/libs/src/circularbuffer.h b/SW/libs/src/circularbuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..42b7c81cc93c1de91f96bf7f35e2e4d94dc15143 --- /dev/null +++ b/SW/libs/src/circularbuffer.h @@ -0,0 +1,81 @@ +#pragma once +/** + * circularbuffer.h v0.1 + * Jakub SkoĹ™epa 2015/8 + */ + +#ifndef CIRCULARBUFFER_H +#define CIRCULARBUFFER_H + +#include <stdint.h> + +template<typename T> +class CircularBuffer +{ + public: + class Iterator { + CircularBuffer *c; + uint8_t p; + public: + Iterator(CircularBuffer* _c, uint8_t _p) : c(_c), p(_p) {} + + void operator++() { + p++; + } + T operator*() { + return c->store[p]; + } + bool operator!=(Iterator i) { + return p!=i.p; + } + }; + + CircularBuffer() { + read_p = 0; + write_p = 0; + } + void operator << (T val) { + store[write_p] = val; + ++write_p; + if(no_freeze) freeze(); + } + uint8_t operator[] (uint8_t pos) { + return store[uint8_t(read_p+pos)]; + } + void advance_readout(uint8_t offset) { + read_p += offset; + } + uint8_t length() { + if(write_p_cp >= read_p) return write_p_cp - read_p; + return -(read_p - write_p_cp); + } + Iterator begin() { + return Iterator(this, read_p); + } + Iterator end() { + return Iterator(this, write_p_cp); + } + uint8_t find(T val) { + uint8_t p = 0; + for(p = 0; p < length(); p++) { + if(store[uint8_t(read_p+p)]==val) return p; + } + return uint8_t(255); + } + void clear() { + read_p = write_p_cp; + } + void freeze() { + write_p_cp = write_p; + } + + bool no_freeze = true; + + protected: + uint8_t write_p_cp; + uint8_t write_p; + uint8_t read_p; + T store[256]; +}; + +#endif // CIRCULARBUFFER_H diff --git a/SW/libs/src/cplusplus.cpp b/SW/libs/src/cplusplus.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fe5819ab49c97966466da9b78a1c1f9f811c502 --- /dev/null +++ b/SW/libs/src/cplusplus.cpp @@ -0,0 +1,30 @@ + +#include "cplusplus.h" +#include <stdlib.h> + + +void * operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void * ptr) +{ + free(ptr); +} + +void * operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete[](void * ptr) +{ + free(ptr); +} + +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; + +void __cxa_pure_virtual(void) {}; diff --git a/SW/libs/src/cplusplus.h b/SW/libs/src/cplusplus.h new file mode 100644 index 0000000000000000000000000000000000000000..d33b9802f618f9966f8b9f924b409561d50d941a --- /dev/null +++ b/SW/libs/src/cplusplus.h @@ -0,0 +1,21 @@ +#pragma once + +#include <stdlib.h> + +//http://www.avrfreaks.net/comment/382641#comment-382641 + +void * operator new(size_t size); +void * operator new[](size_t size); +void operator delete(void * ptr); +void operator delete[](void * ptr); + + +//Templates, virtual inheritance and so on +__extension__ typedef int __guard __attribute__((mode (__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); + +//Pure virtual functions +extern "C" void __cxa_pure_virtual(void); diff --git a/SW/libs/src/external_interrupt.h b/SW/libs/src/external_interrupt.h new file mode 100644 index 0000000000000000000000000000000000000000..54b2b436ed01bf2ef4385e6c34c3a9fe5914e7c6 --- /dev/null +++ b/SW/libs/src/external_interrupt.h @@ -0,0 +1,16 @@ +#pragma once + +#ifndef _EXTERNAL_INTERRUPT_H_ +#define _EXTERNAL_INTERRUPT_H_ + +#if defined (__AVR_ATmega8__) || (__AVR_ATmega8A__) +# include "external_interrupt/ext_irq_m8.h" +#elif defined (__AVR_ATmega16__) || (__AVR_ATmega16A__) || (__AVR_ATmega32__) || (__AVR_ATmega32A__) +# include "external_interrupt/ext_irq_m32.h" +#elif defined (__AVR_ATmega128__) || (__AVR_ATmega128A__) || (__AVR_ATmega1281__) +# include "external_interrupt/ext_irq_m128.h" +#else +# error "This lib don't support this device" +#endif + +#endif diff --git a/SW/libs/src/external_interrupt/ext_irq_m128.cpp b/SW/libs/src/external_interrupt/ext_irq_m128.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30d7463b7afea3ed1b946437345880cf24a4307b --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m128.cpp @@ -0,0 +1,31 @@ +#include "../external_interrupt.h" + +#include <avr/io.h> + +namespace extern_irq +{ + void enable(ext_interrupts interrupt) + { + EIMSK |= (1<<interrupt); + } + + void disable(ext_interrupts interrupt) + { + EIMSK &= ~(1<<interrupt); + } + + void set_sense(ext_interrupts interrupt, irq_senses mode) + { + if (interrupt <= INT3) + { + EICRA &= ~(3<<(interrupt*2)); + EICRA |= (mode<<(interrupt*2)); + } + + else + { + EICRB &= ~(3<<((interrupt-4)*2)); + EICRB |= (3<<((interrupt-4)*2)); + } + } +} //namespace extern_irq diff --git a/SW/libs/src/external_interrupt/ext_irq_m128.h b/SW/libs/src/external_interrupt/ext_irq_m128.h new file mode 100644 index 0000000000000000000000000000000000000000..ae8ff0d7adf9c5b535dd2381a01e07fdcb438786 --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m128.h @@ -0,0 +1,43 @@ +#pragma once + +#ifndef _EXTERNAL_INTERRUPT_H_ +# error "Include external_interrupt.h instead of this file" +#endif + +#include <stdint.h> + +#undef INT0 +#undef INT1 +#undef INT2 +#undef INT3 +#undef INT4 +#undef INT5 +#undef INT6 +#undef INT7 + +namespace extern_irq +{ + enum ext_interrupts + { + INT0, + INT1, + INT2, + INT3, + INT4, + INT5, + INT6, + INT7 + }; + + enum irq_senses + { + low_level = 0, + logic_change = 1, + fallin_edge = 2, + rising_edge = 3 + }; + + extern void enable(ext_interrupts interrupt); + extern void disable(ext_interrupts interrupt); + extern void set_sense(ext_interrupts interrupt, irq_senses mode); +} //namespace extern_irq diff --git a/SW/libs/src/external_interrupt/ext_irq_m32.cpp b/SW/libs/src/external_interrupt/ext_irq_m32.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23b5a2b02210f7752ef29e446cbfae0c856b13ca --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m32.cpp @@ -0,0 +1,141 @@ +#include "../external_interrupt.h" + +#include <avr/io.h> + +namespace extern_irq +{ + //Enable external interupt + void enable_INT0(void) + { + GICR |= (1<<INT0); + } //void enable_INT0(void) + + void enable_INT0(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT0); + break; + + case false: GICR &= ~(1<<INT0); + break; + + default: GICR |= (1<<INT0); + break; + } + } //void enable_INT0(bool status) + + void enable_INT1(void) + { + GICR |= (1<<INT1); + } //void enable_INT1(void) + + void enable_INT1(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT1); + break; + + case false: GICR &= ~(1<<INT1); + break; + + default: GICR |= (1<<INT1); + break; + } + } //void enable_INT1(bool status) + + void enable_INT2(void) + { + GICR |= (1<<INT2); + } //void enable_INT2(void) + + void enable_INT2(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT2); + break; + + case false: GICR &= ~(1<<INT2); + break; + + default: GICR |= (1<<INT2); + break; + } + } //void enable_INT2(bool status) + + //Sense control + void INT0_sense(uint8_t mode) + { + switch (mode) + { + case low_level: MCUCR &= ~(1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + + case logic_change: MCUCR &= ~(1<<ISC01); + MCUCR |= (1<<ISC00); + break; + + case fallin_edge: MCUCR |= (1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + + case rising_edge: MCUCR |= (1<<ISC01); + MCUCR |= (1<<ISC00); + break; + + default: MCUCR &= ~(1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + } + } //void INT0_sense(uint8_t mode) + + void INT1_sense(uint8_t mode) + { + switch (mode) + { + case low_level: MCUCR &= ~(1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + + case logic_change: MCUCR &= ~(1<<ISC11); + MCUCR |= (1<<ISC10); + break; + + case fallin_edge: MCUCR |= (1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + + case rising_edge: MCUCR |= (1<<ISC11); + MCUCR |= (1<<ISC10); + break; + + default: MCUCR &= ~(1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + } + } //void INT1_sense(uint8_t mode) + + + void INT2_sense(uint8_t mode) + { + enable_INT2(false); + GIFR |= (1<<INTF2); + + switch (mode) + { + case rising_edge: MCUCSR &= ~(1<<ISC2); + break; + + case fallin_edge: MCUCSR |= (1<<ISC2); + break; + + default: MCUCSR &= ~(1<<ISC2); + break; + } + + enable_INT2(true); + } //void INT2_sense(uint8_t mode) +} //namespace extern_irq diff --git a/SW/libs/src/external_interrupt/ext_irq_m32.h b/SW/libs/src/external_interrupt/ext_irq_m32.h new file mode 100644 index 0000000000000000000000000000000000000000..27ca1e3988fd43aa0c3494c03c15d3013e2a7fec --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m32.h @@ -0,0 +1,31 @@ +#pragma once + +#ifndef _EXTERNAL_INTERRUPT_H_ +# error "Include external_interrupt.h instead of this file" +#endif + +#include <stdint.h> + +namespace extern_irq +{ + enum interupt_sense + { + low_level = 0, + logic_change = 1, + fallin_edge = 2, + rising_edge = 3 + }; + + extern void enable_INT0(void); + extern void enable_INT0(bool status); + + extern void enable_INT1(void); + extern void enable_INT1(bool status); + + extern void enable_INT2(void); + extern void enable_INT2(bool status); + + extern void INT0_sense(uint8_t mode); + extern void INT1_sense(uint8_t mode); + extern void INT2_sense(uint8_t mode); //only rising & falling edge +} //namespace extern_irq diff --git a/SW/libs/src/external_interrupt/ext_irq_m8.cpp b/SW/libs/src/external_interrupt/ext_irq_m8.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2e2ae06721df3c45fc3dba75c790233a90f1cef --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m8.cpp @@ -0,0 +1,145 @@ +#include "../external_interrupt.h" + +#include <avr/io.h> + +namespace extern_irq +{ + //Enable external interupt + void enable_INT0(void) + { + GICR |= (1<<INT0); + } //void enable_INT0(void) + + void enable_INT0(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT0); + break; + + case false: GICR &= ~(1<<INT0); + break; + + default: GICR |= (1<<INT0); + break; + } + } //void enable_INT0(bool status) + + void enable_INT1(void) + { + GICR |= (1<<INT1); + } //void enable_INT1(void) + + void enable_INT1(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT1); + break; + + case false: GICR &= ~(1<<INT1); + break; + + default: GICR |= (1<<INT1); + break; + } + } //void enable_INT1(bool status) + +/* + void enable_INT2(void) + { + GICR |= (1<<INT2); + } //void enable_INT2(void) + + void enable_INT2(bool status) + { + switch (status) + { + case true: GICR |= (1<<INT2); + break; + + case false: GICR &= ~(1<<INT2); + break; + + default: GICR |= (1<<INT2); + break; + } + } //void enable_INT2(bool status) +*/ + + //Sense control + void INT0_sense(uint8_t mode) + { + switch (mode) + { + case low_level: MCUCR &= ~(1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + + case logic_change: MCUCR &= ~(1<<ISC01); + MCUCR |= (1<<ISC00); + break; + + case fallin_edge: MCUCR |= (1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + + case rising_edge: MCUCR |= (1<<ISC01); + MCUCR |= (1<<ISC00); + break; + + default: MCUCR &= ~(1<<ISC01); + MCUCR &= ~(1<<ISC00); + break; + } + } //void INT0_sense(uint8_t mode) + + void INT1_sense(uint8_t mode) + { + switch (mode) + { + case low_level: MCUCR &= ~(1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + + case logic_change: MCUCR &= ~(1<<ISC11); + MCUCR |= (1<<ISC10); + break; + + case fallin_edge: MCUCR |= (1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + + case rising_edge: MCUCR |= (1<<ISC11); + MCUCR |= (1<<ISC10); + break; + + default: MCUCR &= ~(1<<ISC11); + MCUCR &= ~(1<<ISC10); + break; + } + } //void INT1_sense(uint8_t mode) + +/* + void INT2_sense(uint8_t mode) + { + enable_INT2(false); + GIFR |= (1<<INTF2); + + switch (mode) + { + case rising_edge: MCUCSR &= ~(1<<ISC2); + break; + + case fallin_edge: MCUCSR |= (1<<ISC2); + break; + + default: MCUCSR &= ~(1<<ISC2); + break; + } + + enable_INT2(true); + } //void INT2_sense(uint8_t mode) +*/ + +} //namespace extern_irq diff --git a/SW/libs/src/external_interrupt/ext_irq_m8.h b/SW/libs/src/external_interrupt/ext_irq_m8.h new file mode 100644 index 0000000000000000000000000000000000000000..79b138fd1eb4b5cc127abe40ea9854e7ac63d4d1 --- /dev/null +++ b/SW/libs/src/external_interrupt/ext_irq_m8.h @@ -0,0 +1,27 @@ +#pragma once + +#ifndef _EXTERNAL_INTERRUPT_H_ +# error "Include external_interrupt.h instead of this file" +#endif + +#include <stdint.h> + +namespace extern_irq +{ + enum interupt_sense + { + low_level = 0, + logic_change = 1, + fallin_edge = 2, + rising_edge = 3 + }; + + extern void enable_INT0(void); + extern void enable_INT0(bool status); + + extern void enable_INT1(void); + extern void enable_INT1(bool status); + + extern void INT0_sense(uint8_t mode); + extern void INT1_sense(uint8_t mode); +} //namespace extern_irq diff --git a/SW/libs/src/fifo.h b/SW/libs/src/fifo.h new file mode 100644 index 0000000000000000000000000000000000000000..1967ff0eede77263da2467df7586312597be547e --- /dev/null +++ b/SW/libs/src/fifo.h @@ -0,0 +1,62 @@ +#pragma once + +#include <stdint.h> +#include "cplusplus.h" + +template <typename A_type> class fifo +{ + private: + enum settings + { + QUEUE_LENGHT = 20 + }; + + //Pole a dalšà + A_type queue[QUEUE_LENGHT]; + uint16_t read_position; + uint16_t write_position; + + + public: + + //Konstruktor, destruktor + fifo(); + ~fifo(); + + //Metody pro operace s polem dat + void add(A_type &data); + + A_type read(); + uint8_t check(); +}; + +template <typename A_type> fifo<A_type>::fifo():read_position(0),write_position(0) +{ + +} + +template <typename A_type> fifo<A_type>::~fifo() +{ + +} + +template <typename A_type> void fifo<A_type>::add(A_type &data) +{ + queue[write_position++] = data; + + if (write_position > QUEUE_LENGHT-1) write_position = 0; +} + +template <typename A_type> A_type fifo<A_type>::read() +{ + A_type value = queue[read_position++]; + + if (read_position > QUEUE_LENGHT-1) read_position = 0; + return value; +} + +template <typename A_type> uint8_t fifo<A_type>::check() +{ + if (write_position < read_position) return (QUEUE_LENGHT + write_position - read_position); + else return (write_position - read_position); +} diff --git a/SW/libs/src/gpio.h b/SW/libs/src/gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..1b7d57c479abae6260943dd63b11c6f16f944bae --- /dev/null +++ b/SW/libs/src/gpio.h @@ -0,0 +1,140 @@ + +#pragma once + +#include <avr/io.h> + +class output +{ + private: + volatile uint8_t *ddr; + volatile uint8_t *port; + uint8_t bit; + + public: + output( volatile uint8_t *ddr, + volatile uint8_t *port, + uint8_t bit ) + { + this->ddr = ddr; + this->port = port; + this->bit = bit; + + *ddr |= (1<<bit); + }; + + void on() + { + *port |= (1<<bit); + }; + + void off() + { + *port &= ~(1<<bit); + }; + + void toggle() + { + *port ^= (1<<bit); + }; +}; + +class input +{ + private: + volatile uint8_t *ddr; + volatile uint8_t *port; + volatile uint8_t *pin; + uint8_t bit; + public: + input( volatile uint8_t *ddr, + volatile uint8_t *port, + volatile uint8_t *pin, + uint8_t bit ) + { + this->ddr = ddr; + this->port = port; + this->pin = pin; + this->bit = bit; + + *ddr &= ~(1<<bit); + }; + + ~input() + { + set_pull_up(false); + }; + + void set_pull_up() + { + *port |= (1<<bit); + }; + + void set_pull_up(bool state) + { + if (state) *port |= (1<<bit); + else *port &= ~(1<<bit); + }; + + bool is_set() + { + return !(*pin & (1<<bit) ); + } + ; +}; + + +class io +{ + private: + volatile uint8_t *ddr; + volatile uint8_t *port; + volatile uint8_t *pin; + uint8_t bit; + + public: + enum directions + { + INPUT, + OUTPUT + }; + + public: + io( volatile uint8_t *ddr, + volatile uint8_t *port, + volatile uint8_t *pin, + uint8_t bit ) + { + this->ddr = ddr; + this->port = port; + this->pin = pin; + this->bit = bit; + + *ddr &= ~(1<<bit); + }; + + void set_direction(directions direction) + { + if (direction == OUTPUT) (*ddr |= (1<<bit)); + else *ddr &= ~(1<<bit); + }; + + void on() + { + *port |= (1<<bit); + }; + + void off() + { + *port &= ~(1<<bit); + }; + + void toggle() + { + *port ^= (1<<bit); + }; + + bool is_set() + { + return (*pin & (1<<bit) ); + }; +}; diff --git a/SW/libs/src/jtag.cpp b/SW/libs/src/jtag.cpp new file mode 100644 index 0000000000000000000000000000000000000000..381f1c80fe2a07d826df584e9452df5a832a86e8 --- /dev/null +++ b/SW/libs/src/jtag.cpp @@ -0,0 +1,34 @@ + +#include "jtag.h" + +#include <avr/io.h> +#include <stdint.h> + + +extern void jtag::disable_jtag(void) +{ +#if defined(__AVR_ATmega1281__) + MCUSR = (1<<JTD); + MCUSR = (1<<JTD); +#else + #ifndef __AVR_ATmega8__ + MCUCSR = (1<<JTD); + MCUCSR = (1<<JTD); + #endif +#endif +} + +extern void jtag::enable_jtag(void) +{ +#if defined(__AVR_ATmega1281__) + MCUSR = (1<<JTD); + MCUSR = (1<<JTD); +#else + #ifndef __AVR_ATmega8__ + MCUCSR = 0; + MCUCSR = 0; + #endif +#endif +} + + diff --git a/SW/libs/src/jtag.h b/SW/libs/src/jtag.h new file mode 100644 index 0000000000000000000000000000000000000000..7f2ca2c81bcb6eca4ae1580542b46740adbfcc10 --- /dev/null +++ b/SW/libs/src/jtag.h @@ -0,0 +1,8 @@ +#pragma once + + +namespace jtag +{ + extern void disable_jtag(void); + extern void enable_jtag(void); +} \ No newline at end of file diff --git a/SW/libs/src/macros.h b/SW/libs/src/macros.h new file mode 100644 index 0000000000000000000000000000000000000000..1c3841d08a53fe5882408166cd2b6b9d45bfb279 --- /dev/null +++ b/SW/libs/src/macros.h @@ -0,0 +1,10 @@ +// +// Created by martin.vitek on 15.7.15. +// + +#pragma once + +// Zmena bitu portu, IO registru nebo promenne: +#define setb(bajt,bit) bajt |= 1<<(bit) //nastav bit +#define clrb(bajt,bit) bajt &= ~(1<<(bit)) //nuluj bit +#define negb(bajt,bit) bajt ^= 1<<(bit) //neguj bit diff --git a/SW/libs/src/sht11.cpp b/SW/libs/src/sht11.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a34afa0320b08de168caeb09dc749773064160a --- /dev/null +++ b/SW/libs/src/sht11.cpp @@ -0,0 +1,244 @@ +#include "sht11.h" + +#include "wait.h" + +SHT11::SHT11(io *sda, io *sck) +{ + this->sda = sda; + this->sck = sck; + + sck->set_direction(sck->OUTPUT); + sda->set_direction(sda->OUTPUT); + + sda->on(); + sck->on(); +} + +void SHT11::start_tx() +{ + sda->set_direction(sda->OUTPUT); + sda->on(); + wait_us(20); + + sck->off(); + wait_us(1); + + sck->on(); + wait_us(1); + + sda->off(); + wait_us(1); + + sck->off(); + wait_us(1); + + sck->on(); + wait_us(1); + + sda->on(); + wait_us(1); + + sck->off(); + wait_us(1); +} + +void SHT11::send_command(commands command) +{ + for (uint8_t i=0; i<8; i++) + { + if (command & (1<<(7-i))) sda->on(); + else sda->off(); + wait_us(1); + + sck->on(); + wait_us(1); + + sck->off(); + if (i == 7) sda->on(); + else sda->off(); + wait_us(1); + } + + sda->set_direction(sda->INPUT); + sda->off(); + wait_us(1); + + while (sda->is_set()) ; + + sck->on(); + wait_us(1); + sck->off(); + wait_us(1); + + //while (!sda->is_set()) ; +} + +uint16_t SHT11::read_data() +{ + while (sda->is_set()) ; + + uint16_t result(0); + + for (uint8_t i=0; i<8; i++) + { + sck->on(); + wait_us(1); + if (sda->is_set()) result |= (1<<(15-i)); + sck->off(); + wait_us(1); + } + + sda->set_direction(sda->OUTPUT); + sda->off(); + sck->on(); + wait_us(1); + + sck->off(); + sda->set_direction(sda->INPUT); + wait_us(1); + + for (uint8_t i=0; i<8; i++) + { + sck->on(); + wait_us(1); + if (sda->is_set()) result |= (1<<(7-i)); + sck->off(); + wait_us(1); + } + + return result; +} + +void SHT11::stop_tx() +{ + sda->on(); + sda->set_direction(sda->OUTPUT); + sda->on(); + wait_us(1); + + sck->on(); + wait_us(1); + sck->off(); + wait_us(1); +} + +uint16_t SHT11::measure_temperature() +{ + start_tx(); + send_command(TEMPERATURE); + + uint16_t result = read_data(); + + stop_tx(); + + return result; +} + +uint16_t SHT11::measure_humidity() +{ + start_tx(); + send_command(HUMIDITY); + + uint16_t result = read_data(); + + stop_tx(); + + return result; +} + +void SHT11::initialize() +{ + +} + +void SHT11::communication_reset() +{ + sda->set_direction(sda->OUTPUT); + sda->on(); + + for (uint8_t i=0; i<10; i++) + { + sck->on(); + wait_us(1); + sck->off(); + wait_us(1); + } +} + +[[deprecated]] +void SHT11::reset() +{ + send_command(SOFT_RESET); +} + +bool SHT11::check_communication() +{ + send_command(READ_STATUS_REG); + + while (sda->is_set()) ; + + uint8_t result(0); + + for (uint8_t i=0; i<8; i++) + { + sck->on(); + wait_us(1); + if (sda->is_set()) result |= (1<<(7-i)); + sck->off(); + wait_us(1); + } + + stop_tx(); + + return (bool)result; +} + +void SHT11::start_measuring_temperature() +{ + start_tx(); + send_command(TEMPERATURE); + measuring_temp = true; +} + +void SHT11::start_measuring_humidity() +{ + start_tx(); + send_command(HUMIDITY); + measuring_humi = true; +} + +void SHT11::handler() +{ + if (measuring_temp && sda->is_set()) + { + measuring_temp = false; + + temp_raw = read_data(); + stop_tx(); + + temp_done = true; + } + + if (measuring_humi && sda->is_set()) + { + measuring_humi = false; + humi_raw = read_data(); + stop_tx(); + + humi_done = true; + } +} + +float SHT11::get_temperature() +{ + temperature = (-40.1+0.01*temp_raw); + return temperature; +} + +float SHT11::get_humidity() +{ + float humi_linear = (-2.0468+0.0367*humi_raw+(-1.5955e-6)*humi_raw*humi_raw); + humidity = (temperature - 25.)*(0.01+0.00008*humi_raw)+humi_linear; + + return humidity; +} diff --git a/SW/libs/src/sht11.h b/SW/libs/src/sht11.h new file mode 100644 index 0000000000000000000000000000000000000000..ecaa0b5d501efaded4bbfc03afd2648f7f89d84b --- /dev/null +++ b/SW/libs/src/sht11.h @@ -0,0 +1,64 @@ + +#pragma once + +#include <stdint.h> + +#include "gpio.h" + +class SHT11 +{ + public: + //Definice + enum commands + { + TEMPERATURE = 0x03, + HUMIDITY = 0x05, + READ_STATUS_REG = 0x07, + WRITE_STATUS_REG = 0x06, + SOFT_RESET = 0x1E + }; + + public: + //Instance + io *sda; + io *sck; + + //Measuring stuff + int16_t temp_raw; + int16_t humi_raw; + float temperature; + float humidity; + bool measuring_temp; + bool measuring_humi; + bool temp_done; + bool humi_done; + + + //Metody + void start_tx(); + void send_command(commands command); + uint16_t read_data(); + void stop_tx(); + + public: + SHT11(io *sda, io *sck); + + void initialize(); + bool check_communication(); + void communication_reset(); + void reset(); + + uint16_t measure_temperature(); + uint16_t measure_humidity(); + + void start_measuring_temperature(); + void start_measuring_humidity(); + + void handler(); + + float get_temperature(); + float get_humidity(); + + uint8_t read_status_regster(); + void write_status_register(); +}; diff --git a/SW/libs/src/spi.cpp b/SW/libs/src/spi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac06c49fb9853d1f60d502ef944b03c171da11a6 --- /dev/null +++ b/SW/libs/src/spi.cpp @@ -0,0 +1,202 @@ +#include "spi.h" +#include <avr/interrupt.h> + + +//Konstruktory +spi_class::spi_class() +{ +} //spi_class() + +spi_class::spi_class(operating_modes operating_mode) +{ + set_operating_mode(operating_mode); +} //spi_class(operating_modes mode) + +//Destruktor +spi_class::~spi_class() +{ + disable_SPI(); +} //~spi_class() + + +////////////////////////////////////////////////////////////////////////// +/////////////////////////////Inicializace///////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void spi_class::enable_SPI() +{ + SPCR |= (1<<SPE); +} //enable_SPI() + +void spi_class::enable_SPI(bool status) +{ + if (status) SPCR |= (1<<SPE); + else SPCR &= ~(1<<SPE); +} //enable_SPI(bool status) + +void spi_class::disable_SPI() +{ + SPCR &= ~(1<<SPE); +} //disable_SPI() + +void spi_class::set_operating_mode(operating_modes operating_mode) +{ + if (operating_mode == MASTER) + { + SPI_DDR |= (1<<MOSI_PIN) | (1<<SCK_PIN) | (1<<SS_PIN); + SPI_DDR &= ~(1<<MISO_PIN); + SPI_PORT |= (1<<SS_PIN); + + SPCR |= (1 << MSTR); + } + + else + { + SPI_DDR |= (1<<MISO_PIN); + SPI_DDR &= ~((1<<MOSI_PIN) | (1<<SCK_PIN) | (1<<SS_PIN)); + + SPCR &= ~(1<<MSTR); + } +} //void set_operating_mode(uint8_t mode) + +void spi_class::set_data_mode(data_modes data_mode) +{ + if (data_mode == DATA_MODE_0) + { + set_clock_polarity(RIS_FALL); + set_clock_phase(SAMPLE_SETUP); + } + + else if (data_mode == DATA_MODE_1) + { + set_clock_polarity(RIS_FALL); + set_clock_phase(SETUP_SAMPLE); + } + + else if (data_mode == DATA_MODE_2) + { + set_clock_polarity(FALL_RIS); + set_clock_phase(SAMPLE_SETUP); + } + + else if (data_mode == DATA_MODE_3) + { + set_clock_polarity(FALL_RIS); + set_clock_phase(SETUP_SAMPLE); + } + + else + { + set_clock_polarity(RIS_FALL); + set_clock_phase(SAMPLE_SETUP); + } +} //void set_data_mode(data_modes mode) + +void spi_class::set_data_order(data_order order) +{ + if (order == LSB) SPCR |= (1<<DORD); + else SPCR &= ~(1<<DORD); +} //void set_data_order(data_order data_order) + +void spi_class::set_clock_polarity(clock_polarity polarity) +{ + if (polarity == FALL_RIS) SPCR |= (1<<CPOL); + else SPCR &= ~(1<<CPOL); +} //void set_clock_polarity(clock_polarity polarity) + +void spi_class::set_clock_phase(clock_phase phase) +{ + if (phase == SETUP_SAMPLE) SPCR |= (1<<CPHA); + else SPCR &= ~(1<<CPHA); +} //void set_clock_phase(clock_phase phase) + +void spi_class::set_clock_rate(clock_rates rate) +{ + SPCR &= ~((1<<SPR1) | (1<<SPR0)); + SPSR &= ~(1<<SPI2X); + + SPCR |= (rate & 0b00000011); + SPSR |= (rate & 0b00000100); +} //void set_clock_rate(clock_rates rate) + +void spi_class::enable_interrupt() +{ + SPCR |= (1<<SPIE); +} //void enable_interrupt() + +void spi_class::enable_interrupt(bool status) +{ + if (status) SPCR |= (1<<SPIE); + else SPCR &= ~(1<<SPIE); +} //void enable_interrupt(bool status) + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////Obsluha/////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void spi_class::select(bool state) +{ + if (state) SPI_PORT &= ~(1<<SS_PIN); + else SPI_PORT |= (1<<SS_PIN); +} //void select(bool state) + + +void spi_class::write_data(uint8_t data) +{ + SPDR = data; + + while(!(SPSR & (1<<SPIF))) ; + + uint8_t dummy = SPDR; +} //void write_data(uint8_t data) + +uint8_t spi_class::read_data() +{ + SPDR = 0xff; + + while(!(SPSR & (1<<SPIF))) ; + + return SPDR; +} //uint8_t read_data() + +uint8_t spi_class::write_and_read_data(uint8_t data) +{ + SPDR = data; + + while(!(SPSR & (1<<SPIF))) ; + + return SPDR; +} //uint8_t write_and_read_data(uint8_t data) + + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +//Konstruktor +spi_select_class::spi_select_class(volatile uint8_t *ddr, volatile uint8_t *port, uint8_t pin) +{ + this->ddr = ddr; + this->port = port; + this->pin = pin; + + *ddr |= (1<< pin); + *port |= (1<< pin); +} + +//Destruktor +spi_select_class::~spi_select_class() +{ +} + +void spi_select_class::select(bool status) +{ + if (status) *port &= ~(1<< pin); + else *port |= (1<< pin); +} //void select(bool status) + + +//(c) Martin Vitek 2015 (OK1KVK) \ No newline at end of file diff --git a/SW/libs/src/spi.h b/SW/libs/src/spi.h new file mode 100644 index 0000000000000000000000000000000000000000..94338e46e6b5b3bf27a766c7cce565d4dbb6959c --- /dev/null +++ b/SW/libs/src/spi.h @@ -0,0 +1,127 @@ +#pragma once + +#include <avr/io.h> +#include <stdint.h> + + +#if defined(__AVR_ATmega8__) + #define SPI_DDR DDRB + #define SPI_PORT PORTB + #define MOSI_PIN PB3 + #define MISO_PIN PB4 + #define SCK_PIN PB5 + #define SS_PIN PB2 + +#elif defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__) + #define SPI_DDR DDRB + #define SPI_PORT PORTB + #define MOSI_PIN PB5 + #define MISO_PIN PB6 + #define SCK_PIN PB7 + #define SS_PIN PB4 + +#elif defined(__AVR_ATmega128__) || (__AVR_ATmega1281__) + #define SPI_DDR DDRB + #define SPI_PORT PORTB + #define MOSI_PIN PB2 + #define MISO_PIN PB3 + #define SCK_PIN PB1 + #define SS_PIN PB0 + +#else + #error "This lib don't support this device" +#endif + + +class spi_class +{ + //Definice + public: + enum operating_modes + { + MASTER, + SLAVE + }; + + enum data_modes + { + DATA_MODE_0 = 0, + DATA_MODE_1 = 1, + DATA_MODE_2 = 2, + DATA_MODE_3 = 3 + }; + + enum data_order + { + MSB = 1, + LSB = 0 + }; + + enum clock_polarity + { + RIS_FALL = 0, + FALL_RIS = 1 + }; + + enum clock_phase + { + SAMPLE_SETUP = 0, + SETUP_SAMPLE = 1 + }; + + enum clock_rates + { + F_OSC_2 = 4, + F_OSC_4 = 0, + F_OSC_8 = 5, + F_OSC_16 = 1, + F_OSC_32 = 6, + F_OSC_64 = 2, + F_OSC_64_2 = 7, + F_OSC_128 = 3 + }; + + //Metody + public: + //Konstruktory, destruktor + spi_class(); + spi_class(operating_modes mode); + ~spi_class(); + + //Inicializace + void enable_SPI(); + void enable_SPI(bool status); + void disable_SPI(); + void set_operating_mode(operating_modes operating_mode); + void set_data_mode(data_modes data_mode); + void set_data_order(data_order order); + void set_clock_polarity(clock_polarity polarity); + void set_clock_phase(clock_phase phase); + void set_clock_rate(clock_rates rate); + void enable_interrupt(); + void enable_interrupt(bool status); + + //Obsluha + void select(bool state); + + void write_data(uint8_t data); + uint8_t read_data(); + uint8_t write_and_read_data(uint8_t data); +}; //spi_class + +class spi_select_class +{ + private: + volatile uint8_t *ddr; + volatile uint8_t *port; + uint8_t pin; + + public: + spi_select_class(volatile uint8_t *ddr, volatile uint8_t *port, uint8_t pin); + ~spi_select_class(); + + void select(bool status); +}; //spi_select_class + + +//(c) Martin VĂtek 2015 (OK1KVK) \ No newline at end of file diff --git a/SW/libs/src/usart.cpp b/SW/libs/src/usart.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f16948296c581fbcc1ba173935fb77098e2e55f --- /dev/null +++ b/SW/libs/src/usart.cpp @@ -0,0 +1,346 @@ + +#include "usart.h" + +#include <avr/io.h> +#include <stdint.h> + +////////////////////////////////////////////////////////////////////////// +////////////////////////Konstruktor, destruktor/////////////////////////// +////////////////////////////////////////////////////////////////////////// + +usart::usart(usart_regs ®s): reg(regs) +{ + flush_UDR_buffer(); +} + +usart::~usart() +{ + flush_UDR_buffer(); +} + + +////////////////////////////////////////////////////////////////////////// +/////////////////////////////Inicializace///////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +void usart::set_operating_mode(operation_modes mode) +{ + //Nastaveni modu komunikace + this->mode = mode; + + uint8_t mask = *reg.UCSRC_reg; + mask = *reg.UCSRC_reg; + mask &= ~(1<<UMSEL); + mask |= (1<<URSEL); + *reg.UCSRC_reg = mask; + + + if (mode == ASYNCHRONOUS_NORMAL) *reg.UCSRA_reg &= ~(1<<U2X); + + else if (mode == ASYNCHRONOUS_DOUBLE) *reg.UCSRA_reg |= (1<<U2X); + + else if (mode == SYNCHRONOUS) + { + *reg.UCSRC_reg |= (1<<URSEL) | (1<<UMSEL); + *reg.UCSRA_reg &= ~(1<<U2X); + } + + else return; +} + +void usart::set_baudrate(uint32_t baudrate) +{ + uint16_t baud_value = ((F_CPU/(mode*baudrate))-1); + + *reg.UBRRH_reg = (uint8_t)(baud_value>>8); + *reg.UBRRL_reg = (uint8_t) baud_value; +} + +void usart::set_data_bits(uint8_t bits) +{ + uint8_t mask = *reg.UCSRC_reg; + mask = *reg.UCSRC_reg; + mask &= ~((1<<UCSZ1) | (1<<UCSZ0)); + mask |= (1<<URSEL); + *reg.UCSRC_reg = mask; + *reg.UCSRB_reg &= ~(1<<UCSZ2); + + switch (bits) + { + case 5: + break; + + case 6: *reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ0); + break; + + case 7: *reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1); + break; + + case 8: + *reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); + break; + + case 9: *reg.UCSRB_reg |= (1<<UCSZ2); + *reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0); + break; + + default: + break; + } +} + +void usart::set_stop_bits(uint8_t bits) +{ + switch (bits) + { + case 1: *reg.UCSRC_reg&= ~(1<<USBS) | (1<<URSEL); + break; + + case 2: *reg.UCSRC_reg|= (1<<USBS) | (1<<URSEL); + break; + + default: *reg.UCSRC_reg&= ~(1<<USBS) | (1<<URSEL); + break; + } +} + +void usart::set_parity(parity_modes parity) +{ + switch (parity) + { + case PARITY_NONE: *reg.UCSRC_reg &= (1<<URSEL) | ~(1<<UPM1) | ~(1<<UPM0); + break; + + case PARITY_EVEN: *reg.UCSRC_reg |= (1<<URSEL) | (1<<UPM1) | ~(1<<UPM0); + break; + + case PARITY_ODD: *reg.UCSRC_reg &= (1<<URSEL) | ~(1<<UPM1) | (1<<UPM0); + break; + } +} + +void usart::enable_reciver() +{ + *reg.UCSRB_reg |= (1<<RXEN); +} + +void usart::enable_reciver(bool status) +{ + if (status) *reg.UCSRB_reg |= (1<<RXEN); + else *reg.UCSRB_reg &= ~(1<<RXEN); +} + +void usart::enable_trasmitter() +{ + *reg.UCSRB_reg |= (1<<TXEN); +} + +void usart::enable_trasmitter(bool status) +{ + if (status) *reg.UCSRB_reg |= (1<<TXEN); + else *reg.UCSRB_reg &= ~(1<<TXEN); +} + +void usart::enable_UDRE_interrupt() +{ + *reg.UCSRB_reg |= (1<<UDRIE); +} + +void usart::enable_UDRE_interrupt(bool status) +{ + if (status) *reg.UCSRB_reg |= (1<<UDRIE); + else *reg.UCSRB_reg &= ~(1<<UDRIE); +} + +void usart::enable_TX_complete_interrupt() +{ + *reg.UCSRB_reg |= (1<<TXCIE); +} + +void usart::enable_TX_complete_interrupt(bool status) +{ + if (status) *reg.UCSRB_reg |= (1<<TXCIE); + else *reg.UCSRB_reg &= ~(1<<TXCIE); +} + +void usart::enable_RX_complete_interrupt() +{ + *reg.UCSRB_reg |= (1<<RXCIE); +} + +void usart::enable_RX_complete_interrupt(bool status) +{ + if (status) *reg.UCSRB_reg |= (1<<RXCIE); + else *reg.UCSRB_reg &= ~(1<<RXCIE); +} + +void usart::enable_MPCM() +{ + *reg.UCSRA_reg |= (1<<MPCM); +} + +void usart::enable_MPCM(bool status) +{ + if (status) *reg.UCSRA_reg |= (1<<MPCM); + else *reg.UCSRA_reg &= ~(1<<MPCM); +} + + +////////////////////////////////////////////////////////////////////////// +//////////////////////////////Funkce////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +/////////////////////////////Transmit///////////////////////////////////// +void usart::transmit_char(uint8_t data) +{ + while(!(*reg.UCSRA_reg & (1<<UDRE))) ;; + + *reg.UDR_reg = data; +} + +void usart::transmit_string(const char *data) +{ + while (*data) transmit_char(*(data++)); +} + +void usart::transmit_data(const char *data, uint8_t size) +{ + uint8_t count = 0; + while(count < size) + { + transmit_char(*(data++)); + count++; + } +} + +void usart::transmit_dec32(long data) +{ + unsigned long n; + char ignoruj; + + if(data<0){ + data=-data; + transmit_char('-'); + } + + ignoruj=1; + for(n=1000000000; n>0; n/=10){ + if(data/n){ + transmit_char('0'+data/n); + ignoruj=0; + data%=n; + }else if(!ignoruj){ + transmit_char('0'); + } + } + if(ignoruj) transmit_char('0'); +} + +void usart::transmit_hex8(uint8_t data) +{ + if(data<0xA0) transmit_char((data>>4)+'0'); + else transmit_char((data>>4)+'A'-10); + + if((data&0x0f)<0x0A) transmit_char((data&0x0f)+'0'); + else transmit_char((data&0x0f)+'A'-10); +} + +void usart::transmit_hex16(uint16_t data) +{ + transmit_hex8(data>>8); + transmit_hex8(data&0xff); +} + +void usart::transmit_hex32(uint32_t data) +{ + transmit_hex8(data>>24); + transmit_hex8(data>>16); + transmit_hex8(data>>8); + transmit_hex8(data&0xff); +} + +void usart::transmit_new_line() +{ + transmit_string("\n\r"); +} //void transmit_new_line() + +void usart::transmit_space() +{ + transmit_char(' '); +} //void transmit_space() + +void usart::transmit_binary8(uint8_t data) +{ + for(signed char i = 7; i > -1; i--) + { + transmit_dec32((data&(1<<i))>>i); + } +} //void transmit_binary8(uint8_t data) + +void usart::transmit_binary16(uint16_t data) +{ + for(signed char i = 15; i > -1; i--) + { + transmit_dec32((data&(1<<i))>>i); + } +} //void transmit_binary16(uint16_t data) + +void usart::transmit_binary32(uint32_t data) +{ + for(signed char i = 31; i > -1; i--) + { + transmit_dec32((data&(1<<i))>>i); + } +} //void transmit_binary32(uint32_t data) + +/////////////////////////////Receive////////////////////////////////////// +uint8_t usart::receive_char() +{ + while(!(*reg.UCSRA_reg & (1<<RXC))) ;; + + return *reg.UDR_reg; +} + + +////////////////////////////Obsluha/////////////////////////////////////// +bool usart::check_frame_error() +{ + return (bool)(*reg.UCSRA_reg&(1<<FE)); +} + +bool usart::check_data_over_run() +{ + return (bool)(*reg.UCSRA_reg&(1<<DOR)); +} + +bool usart::check_parity_error() +{ + return (bool)(*reg.UCSRA_reg&(1<<UPE)); +} + + +bool usart::check_usart_recive_complete() +{ + return (bool)(*reg.UCSRA_reg&(1<<RXC)); +} + +bool usart::check_usart_transmit_complete() +{ + return (bool)(*reg.UCSRA_reg&(1<<TXC)); +} + +bool usart::check_usart_data_register_empty() +{ + return (bool)(*reg.UCSRA_reg&(1<<UDRE)); +} + + +void usart::flush_UDR_buffer() +{ + unsigned char dummy1, dummy2; + while( *reg.UCSRA_reg & (1<<RXC) ) dummy1 = *reg.UDR_reg; + dummy2 = dummy1; + dummy1 = dummy2; +} + +//(c) Martin Vitek 2015 (OK1KVK) diff --git a/SW/libs/src/usart.h b/SW/libs/src/usart.h new file mode 100644 index 0000000000000000000000000000000000000000..666ec7b45c328018cd92dbf31248bd8e37b0ae41 --- /dev/null +++ b/SW/libs/src/usart.h @@ -0,0 +1,206 @@ +#pragma once + +#include <avr/io.h> +#include <stdint.h> + +#ifndef UPE + #if defined(PE) + #define UPE PE + #elif defined(UPE0) + #define UPE UPE0 + #else + #warning "Can't define UPE" + #endif +#endif + +#ifndef URSEL + #define URSEL 7 +#endif + +#ifndef UMSEL + #define UMSEL UMSEL00 +#endif + +#ifndef U2X + #define U2X U2X0 +#endif + +#ifndef UCSZ0 + #define UCSZ0 UCSZ00 +#endif + +#ifndef UCSZ1 + #define UCSZ1 UCSZ01 +#endif + +#ifndef UCSZ2 + #define UCSZ2 UCSZ02 +#endif + +#ifndef USBS + #define USBS USBS0 +#endif + +#ifndef UPM0 + #define UPM0 UPM00 +#endif + +#ifndef UPM1 + #define UPM1 UPM01 +#endif + +#ifndef RXEN + #define RXEN RXEN0 +#endif + +#ifndef TXEN + #define TXEN TXEN0 +#endif + +#ifndef UDRIE + #define UDRIE UDRIE0 +#endif + +#ifndef TXCIE + #define TXCIE TXCIE0 +#endif + +#ifndef RXCIE + #define RXCIE RXCIE0 +#endif + +#ifndef MPCM + #define MPCM MPCM0 +#endif + +#ifndef UDRE + #define UDRE UDRE0 +#endif + +#ifndef FE + #define FE FE0 +#endif + +#ifndef DOR + #define DOR DOR0 +#endif + +#ifndef DOR + #define DOR DOR0 +#endif + +#ifndef RXC + #define RXC RXC0 +#endif + +#ifndef TXC + #define TXC TXC0 +#endif + +#ifndef RXEN + #define RXEN RXEN0 +#endif + +#ifndef URSEL + #define URSEL 7 +#endif + +struct usart_regs +{ + volatile uint8_t *UCSRA_reg; + volatile uint8_t *UCSRB_reg; + volatile uint8_t *UCSRC_reg; + volatile uint8_t *UDR_reg; + volatile uint8_t *UBRRL_reg; + volatile uint8_t *UBRRH_reg; +}; + +class usart +{ + public: + enum operation_modes + { + ASYNCHRONOUS_NORMAL = 16, + ASYNCHRONOUS_DOUBLE = 8, + SYNCHRONOUS = 2 + }; + + enum parity_modes + { + PARITY_NONE = 0, + PARITY_EVEN = 2, + PARITY_ODD = 3 + }; + + private: + usart_regs reg; + operation_modes mode; + + public: + //Konstruktor, destruktor + usart(usart_regs ®s); + ~usart(); + + + //USART Init + void set_operating_mode(operation_modes mode); + void set_baudrate(uint32_t baudrate); + void set_data_bits(uint8_t bits); + void set_stop_bits(uint8_t bits); + void set_parity(parity_modes parity); + void enable_reciver(); + void enable_reciver(bool status); + void enable_trasmitter(); + void enable_trasmitter(bool status); + void enable_UDRE_interrupt(); //Data Register Empty + void enable_UDRE_interrupt(bool status); + void enable_TX_complete_interrupt(); + void enable_TX_complete_interrupt(bool status); + void enable_RX_complete_interrupt(); + void enable_RX_complete_interrupt(bool status); + void enable_MPCM(); //Multi Processor Communication Mode + void enable_MPCM(bool status); //Datasheet page 145 + + //USART functions + void transmit_char(uint8_t data); + void transmit_string(const char *data); + void transmit_data(const char *data, uint8_t size); + void transmit_dec32(long data); //Funkce pro odeslani 32bit desitkoveho cisla + void transmit_hex8(uint8_t data); //Funkce pro odeslani 1 bajtoveho Hexu + void transmit_hex16(uint16_t data); //Funkce pro odeslani 2 bajtoveho Hexu + void transmit_hex32(uint32_t data); //Funkce pro odeslani 4 bajtoveho Hexu + void transmit_binary8(uint8_t data); + void transmit_binary16(uint16_t data); + void transmit_binary32(uint32_t data); + + void transmit_new_line(); //Odesle \n\r + void transmit_space(); //Odesle mezeru + + + + uint8_t receive_char(); + + bool check_frame_error(); //Dataseet page 149 + bool check_data_over_run(); //Dataseet page 149 + bool check_parity_error(); //Dataseet page 149 + + bool check_usart_recive_complete(); + bool check_usart_transmit_complete(); + bool check_usart_data_register_empty(); + + void flush_UDR_buffer(); +}; + + +////////////////////////////////////////////////////////////////////////// +//////////////////Vektory preruseni RX, TX, UDRE////////////////////////// +////////////////////////////////////////////////////////////////////////// + +/* +ISR(USART_RXC_vect){}; +ISR(USART_TXC_vect){}; +ISR(USART_UDRE_vect){}; +*/ + + +//(c) Martin Vitek 2015 (OK1KVK) diff --git a/SW/libs/src/wait.cpp b/SW/libs/src/wait.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58a6fb29c4963d1c0048d1c50460fd62af705a33 --- /dev/null +++ b/SW/libs/src/wait.cpp @@ -0,0 +1,60 @@ +/*--------------------------------------------------------------------------- + +soubor: wait.c +verze: 1.0 +datum: 9.1.2012 +popis: + +Cekaci rutiny jsou mnohem uspornejsi nez bezne "delay.h" + +Tento soubor vynikl ze souboru "mojelib.h" jehoz autora bohuzel neznam. + +---------------------------------------------------------------------------*/ +#include "wait.h" + + +//cekej milisekund: +unsigned char reg21 = F_CPU / 60000; // F_CPU = frekv. oscilatoru [Hz], + // (vnitrni konstanta prekladace) +void wait_ms (unsigned int c) +{ + asm("push r20"); + asm("push r21"); + asm("_Wms0:"); + asm("ldi r20,0x14"); + asm("_Wms1:"); + asm("lds r21,reg21"); + asm("_Wms2:"); + asm("dec r21"); + asm("brne _Wms2"); + asm("dec r20"); + asm("brne _Wms1"); + asm("dec r24"); + asm("brne _Wms0"); + asm("dec r25"); + asm("brpl _Wms0"); + asm("pop r21"); + asm("pop r20"); +} + + +//cekej mikrosekund: +unsigned char reg20 = F_CPU / 6000000 + 1; +void wait_us(unsigned int c) +{ + asm("push r20"); + asm("_wus0:"); + asm("lds r20,reg20"); // 1-6MHz: r20=1 6-12MHz: r20=2 + asm("_wus1:"); + asm("dec r20"); + asm("brne _wus1"); + asm("dec r24"); + asm("brne _wus0"); + asm("dec r25"); + asm("brpl _wus0"); + asm("pop r20"); +} + +//eof +//(c) OK1ZKV 2012 & Martin VĂtek 2015 + diff --git a/SW/libs/src/wait.h b/SW/libs/src/wait.h new file mode 100644 index 0000000000000000000000000000000000000000..dcff471b104c0f5131eef5f8acd471cb56d0939e --- /dev/null +++ b/SW/libs/src/wait.h @@ -0,0 +1,21 @@ +/* + * wait.h + * + * Created: 26.3.2013 19:38:53 + * Author: VK + */ +#pragma once + +#ifndef WAIT_H_ +#define WAIT_H_ + +#ifndef F_CPU + #error "F_CPU not defined" +#endif + +// Casove smycky: +void wait_ms (unsigned int c); // cekej milisekund(max65553): +void wait_us (unsigned int c); // cekej mikrosekund(max65553): + + +#endif /* WAIT_H_ */ \ No newline at end of file