From 7b936642adb235f6f4a322bba8fdee5a3f5ce51e Mon Sep 17 00:00:00 2001 From: Carl Klemm Date: Wed, 27 May 2020 20:38:58 +0200 Subject: [PATCH] inital version --- CL56.cpp | 164 ++++++++++++++++++++++++ CL56.h | 83 +++++++++++++ CMakeLists.txt | 59 +++++++++ W433DataReciver.cpp | 231 ++++++++++++++++++++++++++++++++++ W433DataReciver.h | 94 ++++++++++++++ bitrep.h | 9 ++ buttons.h | 48 +++++++ ds1302.cpp | 85 +++++++++++++ ds1302.h | 47 +++++++ eeprom.h | 51 ++++++++ main.cpp | 297 ++++++++++++++++++++++++++++++++++++++++++++ pwm.cpp | 137 ++++++++++++++++++++ pwm.h | 49 ++++++++ ringbuffer.h | 125 +++++++++++++++++++ sensor.h | 21 ++++ serial.cpp | 128 +++++++++++++++++++ serial.h | 37 ++++++ shiftreg.h | 43 +++++++ staticvector.h | 83 +++++++++++++ watchdog.h | 33 +++++ writepin.h | 26 ++++ 21 files changed, 1850 insertions(+) create mode 100644 CL56.cpp create mode 100644 CL56.h create mode 100644 CMakeLists.txt create mode 100644 W433DataReciver.cpp create mode 100644 W433DataReciver.h create mode 100644 bitrep.h create mode 100644 buttons.h create mode 100644 ds1302.cpp create mode 100644 ds1302.h create mode 100644 eeprom.h create mode 100644 main.cpp create mode 100644 pwm.cpp create mode 100644 pwm.h create mode 100755 ringbuffer.h create mode 100644 sensor.h create mode 100644 serial.cpp create mode 100644 serial.h create mode 100644 shiftreg.h create mode 100644 staticvector.h create mode 100644 watchdog.h create mode 100644 writepin.h 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