commit 7b936642adb235f6f4a322bba8fdee5a3f5ce51e Author: Carl Klemm Date: Wed May 27 20:38:58 2020 +0200 inital version diff --git a/CL56.cpp b/CL56.cpp new file mode 100644 index 0000000..f477201 --- /dev/null +++ b/CL56.cpp @@ -0,0 +1,164 @@ +#include "CL56.h" + +DualCl56::DualCl56(ShiftReg<16>* shiftReg): +_shiftReg(shiftReg) +{ + +} + +void DualCl56::tick() +{ + ++_currentLit; + if(_currentLit > 7)_currentLit = 0; + unsigned char bits[2] = {0b10000000>>_currentLit, ~(_segments[_currentLit])}; + _shiftReg->write(reinterpret_cast(&bits)); +} + +void DualCl56::setString(const char string[], const uint8_t dp) +{ + uint_fast8_t i = 0; + for(; i < 8 && string[i] != '\0'; i++) + { + switch (string[i]) + { + case '\0': + case '\n': + case ' ': + _segments[i] = 0; + break; + case '0': + _segments[i] = ZERO; + break; + case '1': + _segments[i] = ONE; + break; + case '2': + _segments[i] = TOW; + break; + case '3': + _segments[i] = THREE; + break; + case '4': + _segments[i] = FOUR; + break; + case '5': + _segments[i] = FIVE; + break; + case '6': + _segments[i] = SIX; + break; + case '7': + _segments[i] = SEVEN; + break; + + case '8': + _segments[i] = EIGT; + break; + + case '9': + _segments[i] = NINE; + break; + case 'a': + case 'A': + _segments[i] = SIGA; + break; + case 'b': + case 'B': + _segments[i] = SIGB; + break; + case 'c': + _segments[i] = SIGc; + break; + case 'C': + _segments[i] = SIGC; + break; + case 'd': + case 'D': + _segments[i] = SIGD; + break; + case 'e': + case 'E': + _segments[i] = SIGE; + break; + case 'f': + case 'F': + _segments[i] = SIGF; + break; + case 'g': + case 'G': + _segments[i] = SIGG; + break; + case 'h': + _segments[i] = SIGh; + break; + case 'H': + _segments[i] = SIGH; + break; + case 'i': + case 'I': + _segments[i] = SIGI; + break; + case 'j': + case 'J': + _segments[i] = SIGJ; + break; + case 'l': + _segments[i] = SIGl; + break; + case 'L': + _segments[i] = SIGL; + break; + case 'n': + case 'N': + _segments[i] = SIGN; + break; + case 'o': + _segments[i] = SIGo; + break; + case 'O': + _segments[i] = SIGO; + break; + case 'p': + case 'P': + _segments[i] = SIGP; + break; + case 'r': + case 'R': + _segments[i] = SIGR; + break; + case 's': + case 'S': + _segments[i] = SIGS; + break; + case 't': + case 'T': + _segments[i] = SIGT; + break; + case 'u': + case 'U': + _segments[i] = SIGU; + break; + case 'v': + case 'V': + _segments[i] = SIGV; + break; + case 'x': + case 'X': + _segments[i] = SIGX; + break; + case 'y': + case 'Y': + _segments[i] = SIGY; + break; + case '-': + _segments[i] = MINUS; + break; + + default: + _segments[i] = INVLD; + break; + } + if( (1 << i) & dp ) _segments[i] |= 1; + } + if(string[i] == '\0') for(; i < 8; i++) _segments[i]&=SEG_DP; +} diff --git a/CL56.h b/CL56.h new file mode 100644 index 0000000..6fe05d9 --- /dev/null +++ b/CL56.h @@ -0,0 +1,83 @@ +#pragma once +#include +#include +#include "shiftreg.h" + +#define SEG_A 0b10000000 +#define SEG_B 0b01000000 +#define SEG_C 0b00100000 +#define SEG_D 0b00010000 +#define SEG_E 0b00001000 +#define SEG_F 0b00000100 +#define SEG_G 0b00000010 +#define SEG_DP 0b00000001 + +class DualCl56 +{ + public: + + static constexpr uint8_t COLEN_A = 0b00000010; + static constexpr uint8_t COLEN_B = 0b00100000; + static constexpr uint8_t DP_A = 0b00000000; + static constexpr uint8_t DP_B = 0b00000001; + static constexpr uint8_t DP_C = 0b00000100; + static constexpr uint8_t DP_D = 0b00001000; + static constexpr uint8_t DP_E = 0b00000000; + static constexpr uint8_t DP_F = 0b00010000; + static constexpr uint8_t DP_G = 0b01000000; + static constexpr uint8_t DP_H = 0b10000000; + + private: + + static constexpr uint8_t ZERO = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F; + static constexpr uint8_t ONE = SEG_B | SEG_C; + static constexpr uint8_t TOW = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D; + static constexpr uint8_t THREE = SEG_A | SEG_B | SEG_C | SEG_D | SEG_G; + static constexpr uint8_t FOUR = SEG_B | SEG_C | SEG_F | SEG_G; + static constexpr uint8_t FIVE =SEG_A | SEG_C | SEG_D | SEG_F | SEG_G; + static constexpr uint8_t SIX = SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SEVEN= SEG_A | SEG_B | SEG_C; + static constexpr uint8_t EIGT = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t NINE = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G; + static constexpr uint8_t MINUS = SEG_G; + static constexpr uint8_t SIGA = SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SIGB = SEG_F | SEG_E | SEG_D | SEG_C | SEG_G; + static constexpr uint8_t SIGC = SEG_A | SEG_D | SEG_E | SEG_F; + static constexpr uint8_t SIGc = SEG_G | SEG_D | SEG_E; + static constexpr uint8_t SIGD = SEG_B | SEG_C | SEG_D | SEG_G | SEG_E; + static constexpr uint8_t SIGE = SEG_A | SEG_D | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SIGF = SEG_A | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SIGG = NINE; + static constexpr uint8_t SIGH = SEG_B | SEG_C | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SIGh = SEG_D | SEG_C | SEG_E | SEG_F | SEG_G; + static constexpr uint8_t SIGI = SEG_E; + static constexpr uint8_t SIGJ = SEG_B | SEG_C | SEG_D; + static constexpr uint8_t SIGL = SEG_F | SEG_E | SEG_D; + static constexpr uint8_t SIGl = SEG_F | SEG_E; + static constexpr uint8_t SIGN = SEG_C | SEG_E | SEG_G; + static constexpr uint8_t SIGO = ZERO; + static constexpr uint8_t SIGo = SEG_E | SEG_G | SEG_C | SEG_D; + static constexpr uint8_t SIGP = SEG_A | SEG_B | SEG_G | SEG_F | SEG_E; + static constexpr uint8_t SIGR = SEG_G | SEG_E; + static constexpr uint8_t SIGS = SEG_A | SEG_C | SEG_D | SEG_F | SEG_G; + static constexpr uint8_t SIGT = SEG_F | SEG_E | SEG_C | SEG_D; + static constexpr uint8_t SIGU = SEG_B | SEG_C | SEG_D | SEG_E | SEG_F; + static constexpr uint8_t SIGV = SIGU; + static constexpr uint8_t SIGX = SIGH; + static constexpr uint8_t SIGY = SEG_F | SEG_B | SEG_G | SEG_E; + static constexpr uint8_t INVLD = SEG_A | SEG_D; + + uint8_t _currentLit = 0; + uint8_t _segments[8] = {SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_G, SEG_DP, FIVE}; + + ShiftReg<16>* _shiftReg; + + public: + + DualCl56(ShiftReg<16>* shiftReg); + + void tick(); + + void setString(const char* string, const uint8_t dp = 0); +}; + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7039ef4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +## A simple CMake file to compile an Arduino project. +## Adjust the settings according to your board. +## The settings here work for the Arduino Uno, Rev. 3. + +# Project name +project(SensorDisplay) + +# CMake version +cmake_minimum_required(VERSION 2.6) + +# Options +# Adjust to your board +set(MCU "atmega328p" CACHE STRING "Processor Type") +set(CPU_SPEED "16000000" CACHE STRING "Speed of the CPU") +set(PORT "/dev/ttyUSB0" CACHE STRING "USB Port") +set(PORT_SPEED "57600" CACHE STRING "Serial Port Speed") +set(PROGRAMMER "stk500v1" CACHE STRING "Programmer Type") +set(COMPILE_FLAGS "" CACHE STRING "Additional Compiler Flags") + +# Set own source files +# Simply list all your C / C++ source (not header!) files here +set(SRC_FILES main.cpp serial.cpp W433DataReciver.cpp CL56.cpp ds1302.cpp) + +# Compiler suite specification +set(CMAKE_C_COMPILER /usr/bin/avr-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/avr-g++) +set(CMAKE_OBJCOPY /usr/bin/avr-objcopy) +set(CMAKE_OBJDUMP /usr/bin/avr-objdump) +set(CMAKE_RANLIB /usr/bin/avr-ranlib) +set(CMAKE_LINKER /usr/bin/avr-ld) + +# Compiler flags +add_definitions(-mmcu=${MCU} -DF_CPU=${CPU_SPEED}) +add_definitions(-s -c -g -Os -flto -Wall -std=c++17 -fno-strict-aliasing) +add_definitions(-fno-exceptions -ffunction-sections -fdata-sections) + +# Linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # remove -rdynamic for C +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") # remove -rdynamic for CXX +set(CMAKE_EXE_LINKER_FLAGS "-Os -Wl,--gc-sections -mmcu=${MCU}") + +add_executable(${PROJECT_NAME} ${ARDUINO_CORE_SRC} ${SRC_FILES}) + +find_program(AR_AVRDUDE NAMES avrdude PATHS /usr/bin NO_DEFAULT_PATH) + +find_program(AR_AVRSIZE NAMES avr-size PATHS /usr/bin NO_DEFAULT_PATH) + +add_custom_target(download + COMMAND ${CMAKE_OBJCOPY} -j .text -j .data -O ihex ${PROJECT_NAME} ${PROJECT_NAME}.hex + COMMAND ${AR_AVRSIZE} -C ${PROJECT_NAME} + COMMAND ${AR_AVRDUDE} -v -p ${MCU} -c ${PROGRAMMER} -P /dev/ttyUSB0 -b 57600 -D -U flash:w:${PROJECT_NAME}.hex + DEPENDS ${PROJECT_NAME} + ) + +add_custom_target(export +COMMAND ${CMAKE_OBJCOPY} -j .text -j .data -O ihex ${PROJECT_NAME} ${PROJECT_NAME}.hex +COMMAND ${AR_AVRSIZE} -C ${PROJECT_NAME} +DEPENDS ${PROJECT_NAME} +) diff --git a/W433DataReciver.cpp b/W433DataReciver.cpp new file mode 100644 index 0000000..6f6e4a5 --- /dev/null +++ b/W433DataReciver.cpp @@ -0,0 +1,231 @@ +#include "W433DataReciver.h" +#include "writepin.h" +#include +#include +#include +#include +#include "serial.h" + +W433DataReciver* W433DataReciver::instance = nullptr; + +W433DataReciver::W433DataReciver(volatile unsigned char* const port , const unsigned char pin, volatile uint16_t * timerRegister, volatile uint8_t* const timerOverflowRegister, void (* const packetCallback)(uint32_t, void*), void* const userData, void (*errorCodeHandler)(uint8_t, void*) ): +_port(port), _pin(pin), _timerRegister(timerRegister), _timerOverflowRegister(timerOverflowRegister), _packetCallback(packetCallback), _errorCodeHandler(errorCodeHandler), _userData(userData) +{ + instance = this; + for(uint8_t i = 0; i < 33; i++) timesBuffer[i] = 0; +} + +W433DataReciver::~W433DataReciver() +{ + instance = nullptr; +} + +void W433DataReciver::staticInterrupt() +{ + if(instance != nullptr) instance->interrupt(); +} + +int8_t W433DataReciver::reciveBit(uint8_t index) +{ + if( + timesBuffer[index] < 0 && + isTime(timesBuffer[index+1], SMALL_TIME, true, SMALL_TIME_TOLERANCE) && + isTime(timesBuffer[index+2], LARGE_TIME, false, LARGE_TIME_TOLERANCE) //&& + //isTime(timesBuffer[index+3], SMALL_TIME, true, SMALL_TIME_TOLERANCE) + ) + { + return 1; + } + else if( + timesBuffer[index] < 0 && + isTime(timesBuffer[index+1], LARGE_TIME, true, LARGE_TIME_TOLERANCE) && + isTime(timesBuffer[index+2], SMALL_TIME, false, SMALL_TIME_TOLERANCE) //&& + //isTime(timesBuffer[index+3], SMALL_TIME, true, SMALL_TIME_TOLERANCE) + ) + { + return 0; + } + else return -1; +} + +void W433DataReciver::waitForReciveIdle(const uint16_t timeoutMs) +{ + uint16_t counter = 0; + while(true) + { + while(counter < timeoutMs && state != LOOKING_FOR_SYNC) + { + _delay_ms(1); + ++counter; + } + _delay_ms(500); + counter+=500; + if(state == LOOKING_FOR_SYNC || counter >= timeoutMs) break; + } +} + + +bool W433DataReciver::isTime(int16_t input, const uint16_t time, const bool state, const uint16_t tollerance) +{ + if((state && input < 0) || (!state && input > 0)) return false; + input = abs(input); + return input < (int16_t)(time+tollerance) && input > (int16_t)(time-tollerance); +} + +bool W433DataReciver::reciveSync(const uint16_t elapsedTime) +{ + if(elapsedTime < SYNC_TIME+SYNC_TIME_TOLERANCE && elapsedTime > SYNC_TIME-SYNC_TIME_TOLERANCE) + { + ++syncCount; + } + else + { + if(syncCount > 4 && syncFailCount < 3) ++syncFailCount; + else + { + //if(syncCount > 7) error(ERR_SYNC_FAIL); + setState(LOOKING_FOR_SYNC); + } + } + if(syncCount > 10) return true; + else return false; +} + +bool W433DataReciver::recivedByte(const uint16_t elapsedTime) +{ + timesBuffer[timesBufferIndex] = readPin(_port, _pin) ? 0-elapsedTime : elapsedTime; + ++timesBufferIndex; + return timesBufferIndex == 32; +} + +uint8_t W433DataReciver::assmbleByte() +{ + uint8_t byte = 0; + for(uint8_t i = 0; i < 8; ++i) + { + int8_t bit = reciveBit(i*4); + if(bit >= 0) byte = byte | (bit << (7-i)); + else + { + setState(LOOKING_FOR_SYNC); + error(ERR_BYTE_ASM); + } + } + timesBufferIndex = 0; + return byte; +} + +void W433DataReciver::error(const uint8_t errorCode) +{ + if(_errorCodeHandler != nullptr) (*_errorCodeHandler)(errorCode, _userData); +} + +void W433DataReciver::setState(const uint8_t stateIn) +{ + TIMSK2 = stateIn == LOOKING_FOR_SYNC; + state = stateIn; + timesBufferIndex = 0; + packetIndex = 0; + syncCount = 0; + syncFailCount = 0; +} + +void W433DataReciver::interrupt() +{ + uint16_t elapsedTime = polarity*(((*_timerOverflowRegister & 0x01) ? *_timerRegister+(UINT16_MAX - previousTime) : *_timerRegister - previousTime)/TICKS_PER_US); + + if(elapsedTime < DISCARD_TIME) + { + if(timesBufferIndex > 0 && elapsedTime + abs(timesBuffer[timesBufferIndex-1]) < LARGE_TIME+LARGE_TIME_TOLERANCE) + { + previousTime = *_timerRegister - elapsedTime - abs(timesBuffer[timesBufferIndex-1]); + timesBufferIndex-=1; + } + return; + } + previousTime = *_timerRegister; + *_timerOverflowRegister = *_timerOverflowRegister | 0x01; + + if(state == LOOKING_FOR_SYNC && reciveSync(elapsedTime)) + { + setState(LOOKING_FOR_SYNC_END); + } + else if(state == LOOKING_FOR_SYNC_END) + { + if(elapsedTime > SYNC_TIME + SYNC_END_TIME_TOLERANCE) + { + if(elapsedTime < LARGE_TIME - LARGE_TIME_TOLERANCE) + { + setState(LOOKING_FOR_SYNC); + error(ERR_NO_SYNC_END); + } + else + { + timesBuffer[0] = -LARGE_TIME; + setState(LOOKING_FOR_SIGNATURE); + ++timesBufferIndex; + } + } + } + else if(state == LOOKING_FOR_SIGNATURE) + { + if(recivedByte(elapsedTime)) + { + uint8_t recivedSignature = assmbleByte(); + if( recivedSignature == signature) setState(RECVING_PACKET); + else + { + error(ERR_WRONG_SIG); + setState(LOOKING_FOR_SYNC); + } + } + } + else if( state == RECVING_PACKET ) + { + + if(recivedByte(elapsedTime)) + { + uint8_t packetByte = assmbleByte(); + + packet = packet | ((uint32_t)packetByte) << ((3-packetIndex)*8); + ++packetIndex; + if(packetIndex > 3) + { + packetIndex = 0; + timesBufferIndex = 0; + setState(RECVING_PACKET_CHECKSUM); + } + } + } + else if(state == RECVING_PACKET_CHECKSUM) + { + if(recivedByte(elapsedTime)) + { + uint8_t recivedChecksum = assmbleByte(); + + volatile uint8_t* buffer = reinterpret_cast(&packet); + + uint8_t computedChecksum = 0; + for(uint8_t j = 0; j < sizeof(packet); j++) for(uint8_t i = 0; i < 8; i++) computedChecksum = computedChecksum + ((buffer[j] & ( 1 << (8 - i))) >> (8 - i)); + //for(uint8_t j = 0; j < sizeof(packet); j++) for(uint8_t i = 0; i < 8; i++) computedChecksum = computedChecksum + (buffer[j] & ( 1 << (8 - i))); + + if(computedChecksum == recivedChecksum) + { + #ifdef USE_RINGBUFFER + _ringBuffer.write(const_cast(buffer), sizeof(packet)); + #endif + if(_packetCallback != nullptr)(*_packetCallback)(packet, _userData); + } + else error(ERR_CHECKSUM); + packet = 0; + setState(LOOKING_FOR_SYNC); + } + } +} + +#ifdef USE_RINGBUFFER +RingBuffer* W433DataReciver::getRingBuffer() +{ + return &_ringBuffer; +} +#endif diff --git a/W433DataReciver.h b/W433DataReciver.h new file mode 100644 index 0000000..fb8f5b1 --- /dev/null +++ b/W433DataReciver.h @@ -0,0 +1,94 @@ +#pragma once +#include +#include "ringbuffer.h" + +//#define USE_RINGBUFFER + +class W433DataReciver +{ +public: + + static constexpr uint8_t RINGBUFFER_LENGTH = 32; + + //errors + static constexpr uint8_t ERR_SYNC_FAIL = 1; + static constexpr uint8_t ERR_NO_SYNC_END = 2; + static constexpr uint8_t ERR_BYTE_ASM = 3; + static constexpr uint8_t ERR_WRONG_SIG = 4; + static constexpr uint8_t ERR_CHECKSUM = 5; + +private: + + static W433DataReciver* instance; + + //constants + static constexpr uint8_t CLOCK_DEVIDER = 1; + static constexpr uint16_t LARGE_TIME = 2000; + static constexpr uint16_t SMALL_TIME = 500; + static constexpr uint16_t SYNC_TIME = 800; + static constexpr uint8_t SYNC_TIME_TOLERANCE = SYNC_TIME*0.20; + static constexpr uint16_t SYNC_END_TIME_TOLERANCE = SYNC_TIME*0.50; + static constexpr uint16_t LARGE_TIME_TOLERANCE = LARGE_TIME*0.30; + static constexpr uint8_t SMALL_TIME_TOLERANCE = SMALL_TIME*0.30; + static constexpr uint16_t DISCARD_TIME = SMALL_TIME*0.6; + static constexpr uint16_t TICKS_PER_US = (F_CPU) / (1000000*CLOCK_DEVIDER) ; + static constexpr uint8_t signature = 0xA5; + + static constexpr int8_t polarity = 1; + + static constexpr uint8_t LOOKING_FOR_SYNC = 0; + static constexpr uint8_t LOOKING_FOR_SYNC_END = 1; + static constexpr uint8_t LOOKING_FOR_SIGNATURE = 2; + static constexpr uint8_t RECVING_PACKET = 3; + static constexpr uint8_t RECVING_PACKET_CHECKSUM = 4; + + //variables + volatile unsigned char *_port; + unsigned char _pin; + + volatile uint16_t *_timerRegister; + volatile uint8_t *_timerOverflowRegister; + +#ifdef USE_RINGBUFFER + RingBuffer _ringBuffer; +#endif + + volatile uint16_t previousTime = 0; + volatile uint8_t timesBufferIndex = 0; + volatile int16_t timesBuffer[33]; + + volatile uint8_t packetIndex = 0; + volatile uint32_t packet = 0; + + void (* const _packetCallback)(uint32_t, void*); + void (* const _errorCodeHandler)(uint8_t, void*); + void* const _userData; + + volatile uint8_t syncCount = 0; + volatile uint8_t syncFailCount = 0; + volatile uint8_t state = 0; + + //private functions + int8_t reciveBit(uint8_t index); + + inline uint8_t assmbleByte(); + inline void setState(const uint8_t stateIn); + inline bool recivedByte(const uint16_t elapsedTime); + inline bool reciveSync(const uint16_t elapsedTime); + + inline void error(const uint8_t errorCode); + + static inline bool isTime(int16_t input, const uint16_t time, const bool state = true, const uint16_t tollerance = 100); + +public: + + W433DataReciver(volatile unsigned char* const port , const unsigned char pin, volatile uint16_t * timerRegister, volatile uint8_t* const timerOverflowRegister, void (*packetCallback)(uint32_t, void*) = nullptr, void* userData = nullptr, void (*errorCodeHandler)(uint8_t, void*) = nullptr ); + ~W433DataReciver(); + static void initTimer(); + static void staticInterrupt(); + void waitForReciveIdle(const uint16_t timeoutMs = 10000); + void interrupt(); +#ifdef USE_RINGBUFFER + RingBuffer* getRingBuffer(); +#endif +}; diff --git a/bitrep.h b/bitrep.h new file mode 100644 index 0000000..8cf1d25 --- /dev/null +++ b/bitrep.h @@ -0,0 +1,9 @@ +#pragma once + +const char *bit_rep[16] = +{ + [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011", + [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111", + [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011", + [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111", +}; diff --git a/buttons.h b/buttons.h new file mode 100644 index 0000000..b6ed441 --- /dev/null +++ b/buttons.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "writepin.h" + +class Buttons +{ + public: + + static constexpr uint8_t PRESSED = 0; + static constexpr uint8_t RELEASED = 2; + static constexpr uint8_t LONG_PRESSED = 1; + static constexpr uint8_t LONG_RELEASED= 3; + + + private: + volatile uint8_t * const pinReg = &PIND; + static constexpr uint16_t usPerTick = 1000; + static constexpr uint8_t button[] = { PD6, PD7 }; + static constexpr uint8_t buttonsAmount = sizeof(button); + uint32_t buttonCount[buttonsAmount] = {}; + + void* _userData; + void (*_eventHandler)(uint8_t index, uint8_t type, void* data); + + public: + Buttons(void (*eventHandler)(uint8_t index, uint8_t type, void* data), void* userData = nullptr): _userData(userData), _eventHandler(eventHandler){} + void tick(); +}; + +void Buttons::tick() +{ + for(uint8_t i = 0; i < buttonsAmount; ++i) + { + if(readPin(pinReg, button[i]) == true) + { + if(buttonCount[i]*usPerTick >= 1000000) _eventHandler(i, LONG_RELEASED, _userData); + else if(buttonCount[i]*usPerTick >= 30000)_eventHandler(i, RELEASED, _userData); + buttonCount[i] = 0; + } + else + { + if(buttonCount[i]*usPerTick == 30000) _eventHandler(i, PRESSED, _userData); + else if(buttonCount[i]*usPerTick == 1000000) _eventHandler(i, LONG_PRESSED, _userData); + ++buttonCount[i]; + } + } +} diff --git a/ds1302.cpp b/ds1302.cpp new file mode 100644 index 0000000..976ffa3 --- /dev/null +++ b/ds1302.cpp @@ -0,0 +1,85 @@ +#include "ds1302.h" +#include "writepin.h" + +DS1302::DS1302(volatile unsigned char *port, volatile unsigned char *pinReg, volatile unsigned char *ddrReg, const unsigned char pinIO, const unsigned char pinCE, const unsigned char _pinSCLK): +_port(port), _pinReg(pinReg), _ddrReg(ddrReg), _pinIO(pinIO), _pinCE(pinCE), _pinSCLK(_pinSCLK) +{ + *_ddrReg |= (1<<_pinCE) | (1<<_pinSCLK) | (1<<_pinIO); + write(REG_WP, 0x00); + uint8_t reg = read(REG_SEC); + write(REG_SEC, reg & ~0b10000000); + write(REG_WP, 0xFF); +} + +void DS1302::write(uint8_t addr, uint8_t value) +{ + setBit(_ddrReg, _pinIO, true); + writePin(_port, _pinCE, true); + for(uint8_t i = 0; i < 8; ++i) + { + writePin(_port, _pinSCLK, false); + writePin(_port, _pinIO, addr & (1<>4); + reg = read(REG_MIN); + time.min = (reg & 0b00001111) + 10*((reg & 0b01110000)>>4); + reg = read(REG_HOUR); + time.hour = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4); + reg = read(REG_DAY); + time.day = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4); + reg = read(REG_MONTH); + time.month = (reg & 0b00001111) + 10*((reg & 0b00110000)>>4); + reg = read(REG_YEAR); + time.year = (reg & 0b00001111) + 10*((reg & 0b11110000)>>4) + EPOCH; + return time; +} +void DS1302::setTime(const Timeval& in) +{ + write(REG_WP, 0x00); + write(REG_SEC, ((in.sec / 10) << 4) | (in.sec % 10) ); + write(REG_MIN, ((in.min / 10) << 4) | (in.min % 10) ); + write(REG_HOUR, ((in.hour / 10) << 4) | (in.hour % 10)); + write(REG_DAY, ((in.day / 10) << 4) | (in.day % 10)); + write(REG_MONTH,((in.month / 10) << 4) | (in.month % 10)); + uint8_t year = in.year - EPOCH; + write(REG_YEAR,((year / 10) << 4) | (year % 10)); + write(REG_WP, 0xFF); +} diff --git a/ds1302.h b/ds1302.h new file mode 100644 index 0000000..d5c74b5 --- /dev/null +++ b/ds1302.h @@ -0,0 +1,47 @@ +#pragma once +#include + +class DS1302 +{ +public: + typedef struct Timeval + { + uint8_t sec; + uint8_t min; + uint8_t hour; + uint8_t day; + uint8_t month; + uint16_t year; + } Timeval; + +private: + + static constexpr uint16_t EPOCH = 2000; + + static constexpr uint8_t REG_SEC = 0x80; + static constexpr uint8_t REG_MIN = 0x82; + static constexpr uint8_t REG_HOUR = 0x84; + static constexpr uint8_t REG_DAY = 0x86; + static constexpr uint8_t REG_MONTH= 0x88; + static constexpr uint8_t REG_YEAR = 0x8C; + static constexpr uint8_t REG_WP = 0x8E; + + static constexpr int8_t writeRegisterOffset = -1; + + volatile unsigned char *_port; + volatile unsigned char *_pinReg; + volatile unsigned char *_ddrReg; + const unsigned char _pinIO; + const unsigned char _pinCE; + const unsigned char _pinSCLK; + + +public: + DS1302(volatile unsigned char *port, volatile unsigned char *pinReg, volatile unsigned char *ddrReg, const unsigned char pinIO, const unsigned char pinCE, const unsigned char pinSCLK); + + void write(const uint8_t addr,const uint8_t value); + uint8_t read(const uint8_t addr); + + Timeval getTime(); + void setTime(const Timeval& in); +}; diff --git a/eeprom.h b/eeprom.h new file mode 100644 index 0000000..ee9b531 --- /dev/null +++ b/eeprom.h @@ -0,0 +1,51 @@ +void EEPROM_write_char(uint16_t address, unsigned char data) +{ + //Wait for completion of previous write + while(EECR & (1< void EEPROM_write_class(uint16_t address, T& in) +{ + EEPROM_write_string( address, reinterpret_cast(&in), sizeof(in)); +} + +template T EEPROM_read_class(uint16_t address) +{ + char data[sizeof(T)]; + EEPROM_read_string( address, data, sizeof(T) ); + return *reinterpret_cast(data); +} + +template void EEPROM_read_class(uint16_t address, T* in) +{ + EEPROM_read_string( address, reinterpret_cast(in), sizeof(T) ); +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..c91b0fd --- /dev/null +++ b/main.cpp @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include "serial.h" +#include "writepin.h" +#include "eeprom.h" +#include "bitrep.h" +#include "watchdog.h" +#include "staticvector.h" +#include "W433DataReciver.h" +#include "CL56.h" +#include "buttons.h" +#include "ds1302.h" +#include "sensor.h" +#include "pwm.h" + +#define MAX_SENSORS 32 +#define COMMAND_BUFFER_SIZE 64 +#define SNPRINTF_BUFFER_SIZE 96 + +void buttonHandler(uint8_t index, uint8_t type, void* data); +SVector sensors; +ShiftReg<16> shiftReg(&PORTB, PB3, PB2, PB1); +DS1302 clock(&PORTC, &PINC, &DDRC, PC0, PC2, PC1); +DualCl56 display(&shiftReg); +Buttons buttons(&buttonHandler); + +uint8_t displaying = 0; + +char buffer[SNPRINTF_BUFFER_SIZE]; + +volatile bool sensorsPaused=true; + +ISR(INT1_vect) +{ + W433DataReciver::staticInterrupt(); +} + +ISR(TIMER2_OVF_vect) +{ + display.tick(); + buttons.tick(); +} + +void buttonHandler(uint8_t index, uint8_t type, void* data) +{ + if(index == 0 && type == Buttons::RELEASED) + { + if(++displaying < sensors.count()+2); + else displaying = 0; + } +} + +void printSensor(const Sensor& sensor, Serial* serial) +{ + serial->write_p(PSTR("SENSOR TYPE: ")); + serial->write(sensor.type); + serial->write_p(PSTR(" ID: ")); + serial->write(sensor.id); + + if(sensor.type == 1) serial->write_p(PSTR(" TEMPERATURE: ")); + else if(sensor.type == 2) serial->write_p(PSTR(" HUMIDITY: ")); + else serial->write_p(PSTR(" FIELD: ")); + serial->write(sensor.field); + serial->putChar('\n'); +} + +void packetHandler(uint32_t packet, void* data) +{ + Serial* serial = reinterpret_cast(data); + + Sensor sensor; + + sensor.field = packet & 0x0000FFFF; + sensor.type = packet >> 24; + sensor.id = (packet & 0x00FF0000) >> 16; + + bool found = false; + for(uint8_t i = 0; i < sensors.count() && !found; ++i) + { + if(sensors[i] == sensor) + { + sensors[i] = sensor; + found = true; + } + } + if(!found) sensors.push_back(sensor); + + if(!sensorsPaused) printSensor(sensor, serial); +} + +void reciverError(uint8_t code, void* userData) +{ + if(!sensorsPaused) + { + Serial* serial = reinterpret_cast(userData); + serial->write_p(PSTR("RECV ERROR CODE: ")); + serial->write(code); + serial->putChar('\n'); + } +} + +inline static void printHelp(Serial* serial) +{ + serial->write_p(PSTR("Available Commands: \n\ + help : Show this prompt.\n\ + date : Show current date and time.\n\ + set [yyyy] [mm] [dd] [hh] [mm] [ss] : Show current date and time.\n\ + pause : pause sensor output.\n\ + resume : resume sensor output.\n\ + dump : Dump epprom.\n\ + free : Show free ram.\n\ + beep : Test buzzer.\n\ + list : List sensors.\n")); +} + + +int freeRAM() +{ + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start: (int) __brkval); +} + +void serialDispatch(Serial* serial, SVector* sensors) +{ + if(serial->dataIsWaiting()) + { + char buffer[COMMAND_BUFFER_SIZE]; + unsigned int length = serial->getString(buffer, COMMAND_BUFFER_SIZE); + if(length > 2) + { + char* token = strtok(buffer, " \n"); + if(strcmp(token, "date") == 0) + { + DS1302::Timeval time = clock.getTime(); + snprintf(buffer, SNPRINTF_BUFFER_SIZE, "%04u.%02u.%02u %02u:%02u:%02u\n", time.year, time.month, time.day, time.hour, time.min, time.sec); + serial->write(buffer, SNPRINTF_BUFFER_SIZE); + } + else if(strcmp(token, "set") == 0) + { + char* year = strtok(NULL, " \n"); + char* mon = strtok(NULL, " \n"); + char* day = strtok(NULL, " \n"); + char* hour = strtok(NULL, " \n"); + char* min = strtok(NULL, " \n"); + char* sec = strtok(NULL, " \n"); + if(year != NULL && mon != NULL && day != NULL && hour != NULL && min != NULL && sec != NULL) + { + DS1302::Timeval time = {atoi(sec),atoi(min),atoi(hour),atoi(day),atoi(mon),atoi(year)}; + clock.setTime(time); + serial->write_p(PSTR("date and time set\n")); + display.setString("SET"); + _delay_ms(1000); + } + else serial->write_p(PSTR("usage: set [yyyy] [mm] [dd] [hh] [mm] [ss]\n")); + } + else if(strcmp(token, "pause") == 0) + { + sensorsPaused = true; + serial->write_p(PSTR("Sensors paused\n")); + } + else if(strcmp(token, "resume") == 0) + { + sensorsPaused = false; + serial->write_p(PSTR("Sensors resumed\n")); + } + else if(strcmp(token, "list") == 0) + { + serial->write_p(PSTR("Sensors:\n")); + for(uint8_t i = 0; i < sensors->count(); ++i) printSensor(sensors->at(i), serial); + serial->write('\n'); + } + else if(strcmp(token, "erase") == 0) + { + for(uint16_t i = 0; i < 1024; i++) EEPROM_write_char(i, 0); + serial->write_p(PSTR("EEPROM erased\n")); + } + else if(strcmp(token, "dump") == 0) + { + for(uint16_t i = 0; i < 1024; i++) + { + if(i != 0) serial->putChar(','); + serial->write((uint16_t)EEPROM_read_char(i)); + } + serial->putChar('\n'); + } + else if(strcmp(token, "free") == 0) + { + serial->write_p(PSTR("Free Ram: ")); + serial->write(freeRAM()); + serial->write_p(PSTR(" Bytes.\n")); + } + else if(strcmp(token, "beep") == 0) + { + for(uint16_t i = 0; i < 250; ++i) + { + writePin(&PORTD, PD4, true); + _delay_us(500); + writePin(&PORTD, PD4, false); + _delay_us(1000); + } + } + else if(strcmp(token, "help") == 0) + { + printHelp(serial); + } + else serial->write_p(PSTR("Not a valid command\n")); + } + } +} + +void displayItems(const DS1302::Timeval& time) +{ + switch(displaying) + { + case 0: + writePin(&PORTB, PB4, time.sec % 2); + snprintf(buffer, 9, " %02u%02u", time.hour, time.min); + display.setString(buffer); + break; + case 1: + writePin(&PORTB, PB4, false); + snprintf(buffer, 9, "%02u%02u%04u", time.day, time.month, time.year); + display.setString(buffer, DualCl56::DP_B | DualCl56::DP_D); + break; + default: + if(displaying == 2 && sensors.count() == 0) display.setString("0 SENSOR"); + else + { + writePin(&PORTB, PB4, false); + snprintf(buffer, 9, "%u%3u%4u", sensors[displaying-2].id, sensors[displaying-2].type, sensors[displaying-2].field); + display.setString(buffer, sensors[displaying-2].type == 1 || sensors[displaying-2].type == 2 ? DualCl56::DP_G : 0); + } + } +} + +int main() +{ + DDRB = (1 << PB1) | ( 1 << PB2) | ( 1 << PB3) | ( 1 << PB4) | ( 1 << PB5); + DDRD = 1<(&serial), &reciverError); + + uint8_t deleteDate = 0; + + serial.write_p(PSTR("Ready\n")); + + while(true) + { + time = clock.getTime(); + displayItems(time); + serialDispatch(&serial, &sensors); + if(deleteDate != time.day) + { + displaying = 0; + sensors.clear(); + deleteDate = time.day; + } + } + + return 0; +} + diff --git a/pwm.cpp b/pwm.cpp new file mode 100644 index 0000000..0fd07c6 --- /dev/null +++ b/pwm.cpp @@ -0,0 +1,137 @@ +#include "pwm.h" + +//16bit + +Pwm16b::Pwm16b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile uint16_t *compareRegisterA, volatile uint16_t *compareRegisterB, volatile uint16_t *inputCaptureRegister, const uint8_t speed, const bool enableA, const bool enableB) +{ + + _timerControlRegisterA = timerControlRegisterA; + _compareRegisterA = compareRegisterA; + _compareRegisterB = compareRegisterB; + + _enableA =enableA; + _enableB =enableB; + + *_timerControlRegisterA = 0x00; + *timerControlRegisterB = 0x00; + *inputCaptureRegister = 0xFFFF; + *timerControlRegisterB |= (1< + +class Pwm16b //TC1 pwm on PB1 & PB2 +{ +private: + volatile unsigned char *_timerControlRegisterA; //TCCRxA + volatile uint16_t *_compareRegisterA; //OCRxA + volatile uint16_t *_compareRegisterB; //OCRxB + bool _enableA; + bool _enableB; + +public: + Pwm16b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile uint16_t *compareRegisterA, volatile uint16_t *compareRegisterB, volatile uint16_t *inputCaptureRegister, const uint8_t speed = 0b00000011, const bool enableA = true, const bool enableB = true); + ~Pwm16b(); + void setDutyA(const uint16_t duty); + void setDutyB(const uint16_t duty); + uint16_t getValueA(); + uint16_t getValueB(); + bool isOn(); + void off(); + void on(); +}; + +class Pwm8b +{ +private: + volatile unsigned char *_timerControlRegisterA; //TCCRxA + volatile unsigned char *_compareRegisterA; //OCRxA + volatile unsigned char *_compareRegisterB; //OCRxB + + bool _enableA; + bool _enableB; + +public: + Pwm8b( volatile unsigned char *timerControlRegisterA, volatile unsigned char *timerControlRegisterB, volatile unsigned char *compareRegisterA, volatile unsigned char *compareRegisterB, const uint8_t speed = 0b00000011, const bool enableA = true, const bool enableB = true); + ~Pwm8b(); + void setDutyA(const uint8_t duty); + void setDutyB(const uint8_t duty); + uint8_t getValueA(); + uint8_t getValueB(); + bool isOn(); + void off(); + void on(); +}; + +#endif diff --git a/ringbuffer.h b/ringbuffer.h new file mode 100755 index 0000000..2796310 --- /dev/null +++ b/ringbuffer.h @@ -0,0 +1,125 @@ +/*UVOS*/ + +/* This file is part of TelemetrySystem. + * + * TelemetrySystem is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License (LGPL) version 3 as published by + * the Free Software Foundation. + * + * TelemetrySystem is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with TelemetrySystem. If not, see . +*/ +#pragma once + +#include + +template < int BUFFER_SIZE, typename T = uint8_t > +class RingBuffer +{ +private: + + volatile uint_fast16_t _headIndex = 0; + volatile uint_fast16_t _tailIndex = 0; + volatile bool _overrun = false; + volatile T _buffer[BUFFER_SIZE]; + +public: + + RingBuffer() + { + flush(); + } + + uint_fast16_t remaining() const volatile + { + return (_headIndex-_tailIndex); + } + + uint_fast16_t remainingCapacity() const volatile + { + return BUFFER_SIZE - (_headIndex-_tailIndex); + } + + bool isOverun() volatile + { + bool returnVal = _overrun; + _overrun = false; + return returnVal; + } + + bool isEmpty() const volatile + { + return _tailIndex >= _headIndex; + } + + T read() volatile + { + if(!isEmpty()) + { + _tailIndex++; + return _buffer[(_tailIndex - 1) % BUFFER_SIZE]; + } + else return '\0'; + } + + unsigned int read( T* buffer, unsigned int length ) volatile + { + unsigned int i = 0; + for(; i < length && !isEmpty(); i++) + { + buffer[i] = read(); + } + return i; + } + + void write( T in ) volatile + { + if (_headIndex - BUFFER_SIZE > 0 && _tailIndex - BUFFER_SIZE > 0) + { + _headIndex -= BUFFER_SIZE; + _tailIndex -= BUFFER_SIZE; + } + _buffer[_headIndex % BUFFER_SIZE] = in; + _headIndex++; + if(remaining() > BUFFER_SIZE) + { + _overrun = true; + _tailIndex = _headIndex - BUFFER_SIZE; + } + } + + void write( T* buffer, const unsigned int length ) volatile + { + for(unsigned int i = 0; i < length; i++) write(buffer[i]); + } + + void flush(T flushCharacter = ' ') volatile + { + _headIndex = 0; + _tailIndex = 0; + for(int i = 0; i < BUFFER_SIZE; i++) _buffer[i] = flushCharacter; + } + + unsigned int getString(T terminator, T* buffer, const unsigned int bufferLength) volatile + { + unsigned int i = 0; + for(; i <= remaining() && i <= BUFFER_SIZE && _buffer[(_tailIndex+i) % BUFFER_SIZE] != terminator; i++); + + if( i < remaining() && i > 0) + { + if(i > bufferLength-1) i = bufferLength-1; + read(buffer, i); + buffer[i]='\0'; + _tailIndex++; + } + else if(i == 0) _tailIndex++; + else i = 0; + + return i; + } +}; diff --git a/sensor.h b/sensor.h new file mode 100644 index 0000000..9ce3548 --- /dev/null +++ b/sensor.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class Sensor +{ +public: + uint8_t id; + uint8_t type; + int16_t field; + + Sensor(){} + Sensor(const uint8_t idIn, const uint8_t typeIn, const uint16_t fieldIn): + id(idIn), type(typeIn), field(fieldIn) + {} + + bool operator==(const Sensor& in) + { + return id == in.id && type == in.type; + } + +}; diff --git a/serial.cpp b/serial.cpp new file mode 100644 index 0000000..be7b44c --- /dev/null +++ b/serial.cpp @@ -0,0 +1,128 @@ +#include "serial.h" +#include "ringbuffer.h" + +volatile RingBuffer rxBuffer; + +bool stopped = false; + +ISR(USART_RX_vect) //I have seen worse interrupt sintax +{ + rxBuffer.write(UDR0); + if(serialFlowControl && !stopped && rxBuffer.remainingCapacity() < 32) + { + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = 0x13; + stopped = true; + } +} + +Serial::Serial() +{ + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); + UCSR0B = _BV(RXEN0) | _BV(TXEN0); //Enable RX and TX + UCSR0B |= (1 << RXCIE0); //Enable Rx interuppt + sei(); +} + +void Serial::putChar(const char c) +{ + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; +} + +void Serial::write(const char* in, const unsigned int length) +{ + for(unsigned int i = 0; i < length && in[i] != '\0'; i++) + { + putChar(in[i]); + } +} + +void Serial::write_p(const char in[]) +{ + cli(); + char ch = pgm_read_byte(in); + while (ch != '\0') + { + putChar(ch); + in++; + ch = pgm_read_byte(in); + } + sei(); +} + +void Serial::write(const char in[]) +{ + for(unsigned int i = 0; i < strlen(in); i++) + { + putChar(in[i]); + } +} + + +void Serial::write(int32_t in) +{ + if(in == 0) + { + putChar('0'); + } + else + { + bool flag = false; + char str[64] = { 0 }; + int16_t i = 62; + if (in < 0) + { + flag = true; + in = abs(in); + } + + while (in != 0 && i > 0) + { + str[i--] = (in % 10) + '0'; + in /= 10; + } + + if (flag) str[i--] = '-'; + write(str + i + 1, 64-(i+1)); + } +} + +bool Serial::dataIsWaiting() +{ + return !rxBuffer.isEmpty(); +} + +char Serial::getChar() +{ + if(!rxBuffer.isEmpty()) + { + if(serialFlowControl && stopped && rxBuffer.remainingCapacity() > 32 ) + { + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = 0x11; + stopped = false; + } + return rxBuffer.read(); + } + else return '\0'; +} + +unsigned int Serial::getString(char* buffer, const int bufferLength) +{ + return rxBuffer.getString(_terminator, (uint8_t*)buffer, bufferLength); +} + +unsigned int Serial::read(char* buffer, const unsigned int length ) +{ + return rxBuffer.read((uint8_t*)buffer, length); +} + +void Serial::flush() +{ + rxBuffer.flush(); +} + +void Serial::setTerminator(char terminator){_terminator = terminator;} diff --git a/serial.h b/serial.h new file mode 100644 index 0000000..3610289 --- /dev/null +++ b/serial.h @@ -0,0 +1,37 @@ +#ifndef SERIAL_H +#define SERIAL_H + +#define BAUD 38400 +#define SERIAL_BUFFER_SIZE 256 + +#include +#include +#include +#include +#include +#include + +const bool serialFlowControl = false; + +class Serial +{ +private: + char _terminator = '\n'; + +public: + Serial(); + void putChar(const char c); + void write(const char* in, const unsigned int length); + void write(const char in[]); + void write_p(const char in[]); //for flash space strigns + void write(const int32_t in); + unsigned int read( char* buffer, const unsigned int length ); + bool dataIsWaiting(); + char getChar(); + unsigned int getString(char* buffer, const int bufferLength); + void flush(); + void setTerminator(const char terminator); +}; + +#endif + diff --git a/shiftreg.h b/shiftreg.h new file mode 100644 index 0000000..dac7728 --- /dev/null +++ b/shiftreg.h @@ -0,0 +1,43 @@ +#pragma once +#include +template class ShiftReg +{ +private: + static constexpr int BYTES = (BITS % 8 == 0) ? (BITS/8) : (BITS/8+1); + + volatile unsigned char *_port; + const unsigned char _pinSer; + const unsigned char _pinSerClk; + const unsigned char _pinRClk; + +public: + + ShiftReg(volatile unsigned char* const port, const unsigned char pinSer, const unsigned char pinSerClk, const unsigned char pinRClk): + _port(port), _pinSer(pinSer), _pinSerClk(pinSerClk), _pinRClk(pinRClk) + { + clear(); + } + void write(const unsigned char * const in) + { + *_port &= ~((1<<_pinSer) | (1<<_pinSerClk)); + *_port |= 1<<_pinRClk; + for(unsigned char i = 0; i < BITS; ++i) + { + *_port &= ~(1 << _pinSerClk); + in[i/8] & (1<<(i%8)) ? (*_port |= (1 << _pinSer)) : (*_port &= ~(1 << _pinSer)); + *_port |= (1 << _pinSerClk); + } + *_port &= ~(1<<_pinRClk); + } + void clear() + { + *_port &= ~((1<<_pinSer) | (1<<_pinSerClk)); + *_port |= 1<<_pinRClk; + for(unsigned char i = 0; i < BITS; ++i) + { + *_port &= ~(1 << _pinSerClk); + *_port |= (1 << _pinSerClk); + } + *_port &= ~(1<<_pinRClk); + } +}; diff --git a/staticvector.h b/staticvector.h new file mode 100644 index 0000000..786456b --- /dev/null +++ b/staticvector.h @@ -0,0 +1,83 @@ +#pragma once +#include + +template class SVector +{ +private: + size_t stored = 0; + + T array[size]; + +public: + + T* data() + { + return array; + } + + T& operator[](size_t i) + { + return array[i]; + } + + T& at(size_t i) + { + return array[i]; + } + + T& front() + { + return array[0]; + } + + T& back() + { + return array[stored-1]; + } + + bool empty() const + { + return stored == 0 ? true : false; + } + + size_t count() const + { + return stored; + } + + constexpr size_t maxSize() const + { + return size; + } + + size_t remainingCapacity() const + { + return size - stored; + } + + bool push_back(const T in) + { + if( remainingCapacity() != 0) + { + array[stored] = in; + ++stored; + return true; + } + else return false; + } + + bool erase(size_t position) + { + if(position > stored) return false; + array[position].~T(); + --stored; + for( size_t i = position; i < stored; i++ ) memcpy(&array[i], &array[i+1], sizeof(T)); + return true; + } + + void clear() + { + for( size_t i = 0; i < stored; i++ ) array[i].~T(); + stored = 0; + } +}; diff --git a/watchdog.h b/watchdog.h new file mode 100644 index 0000000..de49320 --- /dev/null +++ b/watchdog.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#define wdt_set(value) \ + __asm__ __volatile__ ( \ + "in __tmp_reg__,__SREG__" "\n\t" \ + "cli" "\n\t" \ + "wdr" "\n\t" \ + "sts %0,%1" "\n\t" \ + "out __SREG__,__tmp_reg__" "\n\t" \ + "sts %0,%2" \ + : /* no outputs */ \ + : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ + "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ + "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ + _BV(WDIE) | (value & 0x07)) ) \ + : "r0" \ + ) + + +#define wdt_off(x) \ + __asm__ __volatile__ ( \ + "in __tmp_reg__,__SREG__" "\n\t" \ + "cli" "\n\t" \ + "wdr" "\n\t" \ + "sts %0,%1" "\n\t" \ + "sts %0,%2" \ + : /* no outputs */ \ + : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ + "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ + "r" ((uint8_t) (0x00)) \ + : "r0" \ + ) diff --git a/writepin.h b/writepin.h new file mode 100644 index 0000000..78db970 --- /dev/null +++ b/writepin.h @@ -0,0 +1,26 @@ +#ifndef WRITEPIN_H +#define WRITEPIN_H +#include + + +inline void writePin(volatile unsigned char *port, const unsigned char pin, const bool state) //waste 2 cycles +{ + *port &= ~(1 << pin); + if(state) *port |= (1 << pin); +} + +inline void setBit( volatile unsigned char *reg, const unsigned char bit, bool value ) +{ + writePin(reg, bit, value); +} + + +inline void setDirection( volatile unsigned char *portDirReg, const unsigned char pin, bool makeOutput ) +{ + writePin(portDirReg, pin, makeOutput); +} + +inline bool readPin( volatile unsigned char *inPort, const unsigned char pin){ return (bool) (*inPort & (1 << pin));} + + +#endif