Mercurial > katka
changeset 16:7c312f2f6291
Update the code to work on current robot
| author | Radomir Dopieralski <sheep-devel@sheep.art.pl> |
|---|---|
| date | Thu, 11 Jun 2015 13:46:30 +0200 |
| parents | 61de3195b19d |
| children | 3265a2f99027 |
| files | katka/IRLremote.cpp katka/IRLremote.h katka/creep.ino katka/ir.ino katka/katka.ino katka/servos.ino |
| diffstat | 6 files changed, 866 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/katka/IRLremote.cpp Thu Jun 11 13:46:30 2015 +0200 @@ -0,0 +1,50 @@ +/* +Copyright (c) 2014 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "IRLremote.h" + +//================================================================================ +// User function helper +//================================================================================ + +// ensure available() returns false +uint8_t IRLProtocol = 0; +uint16_t IRLAddress = 0; +uint32_t IRLCommand = 0; + +// Called when directly received correct IR Signal +// Do not use Serial inside, it can crash your Arduino! +void IREvent(uint8_t protocol, uint16_t address, uint32_t command) { + // For no user function set we need to pause IR + // to not overwrite the actual values until they are read. + if (IRLProtocol) return; + IRLAddress = address; + IRLCommand = command; + IRLProtocol = protocol; +} + +void decodeIR(const uint16_t duration){ + // add your own protocols here or create your own decoding function + // you can overwrite this function in your .ino file + decodeAll(duration); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/katka/IRLremote.h Thu Jun 11 13:46:30 2015 +0200 @@ -0,0 +1,778 @@ +/* +Copyright (c) 2014 NicoHood +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef IRLREMOTE_H +#define IRLREMOTE_H + +#include <Arduino.h> + +//missing 1.0.6 definition workaround +#if ARDUINO == 106 +#define NOT_AN_INTERRUPT -1 +#endif + +// board type detection +#if defined(__MK20DX128__) || defined(__MK20DX256__) +#define IRLREMOTE_ARM +#define IRLREMOTE_TEENSY3 +#elif defined(__SAM3X8E__) +#define IRLREMOTE_ARM +#define IRLREMOTE_DUE +#else +// default to assuming everything else is avr for now +#define IRLREMOTE_AVR +#endif + +// delay_basic is only for avrs. with ARM sending is currently not possible +#ifdef IRLREMOTE_AVR +#include <util/delay_basic.h> +#endif + +//================================================================================ +// Definitions +//================================================================================ + +//NEC +//IRP notation: {38.4k,564}<1,-1|1,-3>(16,-8,D:8,S:8,F:8,~F:8,1,-78,(16,-4,1,-173)*) +// Lead + Space logic +#define NEC_HZ 38400 +#define NEC_PULSE 564UL +#define NEC_BLOCKS 4 +#define NEC_ADDRESS_LENGTH 16 +#define NEC_COMMAND_LENGTH 16 +#define NEC_LENGTH 2 + NEC_BLOCKS*8*2 // 2 for lead + space, each block has 8bits: mark and space +#define NEC_TIMEOUT NEC_PULSE*173 +#define NEC_MARK_LEAD NEC_PULSE*16 +#define NEC_SPACE_LEAD NEC_PULSE*8 +#define NEC_SPACE_HOLDING NEC_PULSE*4 +#define NEC_MARK_ZERO NEC_PULSE*1 +#define NEC_MARK_ONE NEC_PULSE*1 +#define NEC_SPACE_ZERO NEC_PULSE*1 +#define NEC_SPACE_ONE NEC_PULSE*3 + +//PANASONIC +//IRP notation: {37k,432}<1,-1|1,-3>(8,-4,3:8,1:8,D:8,S:8,F:8,(D^S^F):8,1,-173)+ +// Lead + Space logic +#define PANASONIC_HZ 37000 +#define PANASONIC_PULSE 432UL +#define PANASONIC_BLOCKS 6 +#define PANASONIC_ADDRESS_LENGTH 16 +#define PANASONIC_COMMAND_LENGTH 32 +#define PANASONIC_LENGTH 2 + PANASONIC_BLOCKS*8*2 // 2 for lead + space, each block has 8bits: mark and space +#define PANASONIC_TIMEOUT PANASONIC_PULSE*173 +#define PANASONIC_MARK_LEAD PANASONIC_PULSE*8 +#define PANASONIC_SPACE_LEAD PANASONIC_PULSE*4 +#define PANASONIC_SPACE_HOLDING 0 // no holding function in this protocol +#define PANASONIC_MARK_ZERO PANASONIC_PULSE*1 +#define PANASONIC_MARK_ONE PANASONIC_PULSE*1 +#define PANASONIC_SPACE_ZERO PANASONIC_PULSE*1 +#define PANASONIC_SPACE_ONE PANASONIC_PULSE*3 + +/* +Panasonic pulse demonstration: + +*---------| |------------| |---------| |---| ... -| |--------- +* | | | | | | | ... | | +* | | | | | | | ... | | +* |------------------------| |---| |---| |- ... |---| +* | Lead Mark | Lead Space | Logical 1 | Log 0 | Data |End| + +*/ + +//SONY 8, 12, 15, 20 +//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:8,^22200) +//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:5,^45m)+ +//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:8,^45m)+ +//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:5,S:8,^45m) + +// Lead + Mark logic +#define SONY_HZ 40000 +#define SONY_PULSE 600UL +#define SONY_BLOCKS_8 1 +#define SONY_BLOCKS_12 2 +#define SONY_BLOCKS_15 2 +#define SONY_BLOCKS_20 3 +#define SONY_ADDRESS_LENGTH_8 0 +#define SONY_ADDRESS_LENGTH_12 5 +#define SONY_ADDRESS_LENGTH_15 8 +#define SONY_ADDRESS_LENGTH_20 13 +#define SONY_COMMAND_LENGTH_8 8 +#define SONY_COMMAND_LENGTH_12 7 +#define SONY_COMMAND_LENGTH_15 7 +#define SONY_COMMAND_LENGTH_20 7 +#define SONY_LENGTH_8 2 + (8-1)*2 // 2 for lead + space, -1 for mark end, 8 bit +#define SONY_LENGTH_12 2 + (7+5-1)*2 // 2 for lead + space, -1 for mark end, 12 bit +#define SONY_LENGTH_15 2 + (7+8-1)*2 // 2 for lead + space, -1 for mark end, 15 bit +#define SONY_LENGTH_20 2 + (7+5+8-1)*2 // 2 for lead + space, -1 for mark end, 20 bit +#define SONY_TIMEOUT_8 22200 +#define SONY_TIMEOUT 45000 // 12, 15, 20 have the same timeout +#define SONY_MARK_LEAD SONY_PULSE*4 +#define SONY_SPACE_LEAD SONY_PULSE*1 +#define SONY_SPACE_HOLDING 0 // no holding function in this protocol +#define SONY_MARK_ZERO SONY_PULSE*1 +#define SONY_MARK_ONE SONY_PULSE*2 +#define SONY_SPACE_ZERO SONY_PULSE*1 +#define SONY_SPACE_ONE SONY_PULSE*1 + +typedef enum IRType{ + IR_NO_PROTOCOL, // 0 + IR_USER, // 1 + IR_ALL, // 2 + IR_NEC, // ... + IR_PANASONIC, + IR_SONY8, + IR_SONY12, + IR_SONY15, + IR_SONY20, + // add new protocols here + IR_RAW, +}; + +// definitions to use decoding functions with extra accuracy +#define IR_EXTRA_ACCURACY true +#define IR_NO_EXTRA_ACCURACY false + +// definition for sending to determine what should be send first +#define IR_ADDRESS_FIRST true +#define IR_COMMAND_FIRST false + +// definition to convert an uint8_t array to an uint16_t/uint32_t at any position (thx timeage!) +#define UINT16_AT_OFFSET(p_to_8, offset) ((uint16_t)*((const uint16_t *)((p_to_8)+(offset)))) +#define UINT32_AT_OFFSET(p_to_8, offset) ((uint32_t)*((const uint32_t *)((p_to_8)+(offset)))) + +// definition to get the higher value +#define MAX(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +// definition to get the lower value +#define MIN(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +//================================================================================ +// Prototypes +//================================================================================ + +// attach the interrupt function +template <IRType irType> +inline void IRLbegin(const uint8_t interrupt) __attribute__((always_inline)); + +// dettach the interrupt function +inline void IRLend(const uint8_t interrupt) __attribute__((always_inline)); + +// variables for IR processing if no user function was set +extern uint8_t IRLProtocol; +extern uint16_t IRLAddress; +extern uint32_t IRLCommand; + +// functions to use if no user function was set +inline bool IRLavailable(void) __attribute__((always_inline)); +inline void IRLreset(void) __attribute__((always_inline)); +inline uint8_t IRLgetProtocol(void) __attribute__((always_inline)); +inline uint16_t IRLgetAddress(void) __attribute__((always_inline)); +inline uint32_t IRLgetCommand(void) __attribute__((always_inline)); + +// function called on a valid IR event, must be overwritten by the user +void __attribute__((weak)) IREvent(uint8_t protocol, uint16_t address, uint32_t command); + +// optinal user function called when the user wants to implement its own decoding function +void __attribute__((weak)) decodeIR(const uint16_t duration); + +// called by interrupt CHANGE +template <IRType irType> +inline void IRLinterrupt(void) __attribute__((always_inline)); + +// special decode function for each protocol +inline void decodeAll(const uint16_t duration) __attribute__((always_inline)); +template <bool extraAccuracy> inline void decodeNec(const uint16_t duration); +template <bool extraAccuracy> inline void decodePanasonic(const uint16_t duration) __attribute__((always_inline)); +template <bool extraAccuracy> inline void decodeSony8(const uint16_t duration); +template <bool extraAccuracy> inline void decodeSony12(const uint16_t duration); +template <bool extraAccuracy> inline void decodeSony15(const uint16_t duration); +template <bool extraAccuracy> inline void decodeSony20(const uint16_t duration); +inline void decodeRaw(const uint16_t duration) __attribute__((always_inline)); + +// functions to check if the received data is valid with the protocol checksums +inline bool IRLcheckInverse0(uint8_t data[]) __attribute__((always_inline)); +inline bool IRLcheckInverse1(uint8_t data[]) __attribute__((always_inline)); +inline bool IRLcheckHolding(uint8_t data[]) __attribute__((always_inline)); +inline bool IRLcheckXOR0(uint8_t data[]) __attribute__((always_inline)); + +// default decoder helper function +template <uint8_t irLength, uint16_t timeoutThreshold, uint16_t markLeadThreshold, uint16_t spaceLeadThreshold, + uint16_t spaceLeadHoldingThreshold, uint16_t markThreshold, uint16_t spaceThreshold, + uint16_t markTimeout, uint16_t spaceTimeout> + inline bool IRLdecode(uint16_t duration, uint8_t data[]) __attribute__((always_inline)); + +// functions to send the protocol +template <IRType irType> +inline void IRLwrite(const uint8_t pin, uint16_t address, uint32_t command) __attribute__((always_inline)); + +template <uint8_t addressLength, uint8_t commandLength, + uint16_t Hz, bool addressFirst, + uint16_t markLead, uint16_t spaceLead, + uint16_t markZero, uint16_t markOne, + uint16_t spaceZero, uint16_t spaceOne> + inline void IRLsend(volatile uint8_t * outPort, uint8_t bitmask, uint16_t address, uint32_t command) __attribute__((always_inline)); + +// functions to set the pin high or low (with bitbang pwm) +inline void IRLmark(const uint16_t Hz, volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) __attribute__((always_inline)); +inline void IRLspace(volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) __attribute__((always_inline)); + +//================================================================================ +// Inline Implementations (receive) +//================================================================================ + +template <IRType irType> +void IRLbegin(const uint8_t interrupt){ + // attach the function that decodes the signals + attachInterrupt(interrupt, IRLinterrupt<irType>, CHANGE); +} + +void IRLend(const uint8_t interrupt){ + // release the interrupt, if its NOT_AN_INTERRUPT the detach function does nothing + detachInterrupt(interrupt); + // also make sure to call reset() after end() if you use the intern reading functions +} + +bool IRLavailable(void){ + return IRLProtocol; +} + +void IRLreset(void){ + IRLProtocol = 0; +} + +uint8_t IRLgetProtocol(void){ + return IRLProtocol; +} + +uint16_t IRLgetAddress(void){ + return IRLAddress; +} + +uint32_t IRLgetCommand(void){ + return IRLCommand; +} + +template <IRType irType> +void IRLinterrupt(void){ + //save the duration between the last reading + static uint32_t lastTime = 0; + uint32_t time = micros(); + uint32_t duration_32 = time - lastTime; + lastTime = time; + + // calculate 16 bit duration. On overflow set duration to a clear timeout + uint16_t duration = 0xFFFF; + if (duration_32 <= 0xFFFF) + duration = duration_32; + + // determinate which decode function must be called + switch (irType){ + case IR_USER: + // userfunction that can be overwritten + decodeIR(duration); + break; + case IR_ALL: + decodeAll(duration); + break; + case IR_NEC: + decodeNec<IR_NO_EXTRA_ACCURACY>(duration); + break; + case IR_PANASONIC: + decodePanasonic<IR_NO_EXTRA_ACCURACY>(duration); + break; + //case IR_SONY8: + // decodeSony8<IR_NO_EXTRA_ACCURACY>(duration); + // break; + case IR_SONY12: + decodeSony12<IR_NO_EXTRA_ACCURACY>(duration); + break; + //case IR_SONY15: + // decodeSony15<IR_NO_EXTRA_ACCURACY>(duration); + // break; + //case IR_SONY20: + // decodeSony20<IR_NO_EXTRA_ACCURACY>(duration); + // break; + case IR_RAW: + decodeRaw(duration); + break; + } +} + +void decodeAll(const uint16_t duration){ + // go through all known protocols and decode with more (resource unfriendly) accuration + decodeNec<IR_EXTRA_ACCURACY>(duration); + decodePanasonic<IR_EXTRA_ACCURACY>(duration); + decodeSony12<IR_EXTRA_ACCURACY>(duration); +} + +template <bool extraAccuracy> void decodeNec(const uint16_t duration){ + // temporary buffer to hold bytes for decoding this protocol + static uint8_t data[NEC_BLOCKS]; + + // pass the duration to the decoding function + bool newInput; + if (extraAccuracy) // no accuracy set at the moment, no conflict detected yet + newInput = IRLdecode <NEC_LENGTH, (NEC_TIMEOUT + NEC_MARK_LEAD) / 2, // irLength, timeoutThreshold + (NEC_MARK_LEAD + NEC_SPACE_ONE) / 2, (NEC_SPACE_LEAD + NEC_SPACE_HOLDING) / 2, // markLeadThreshold, spaceLeadThreshold + (NEC_SPACE_HOLDING + NEC_SPACE_ONE) / 2, 0, // spaceLeadHoldingThreshold, markThreshold + (NEC_SPACE_ONE + NEC_SPACE_ZERO) / 2, // spaceThreshold + 0, 0>// markTimeout, spaceTimeout + (duration, data); + else + newInput = IRLdecode <NEC_LENGTH, (NEC_TIMEOUT + NEC_MARK_LEAD) / 2, // irLength, timeoutThreshold + (NEC_MARK_LEAD + NEC_SPACE_ONE) / 2, (NEC_SPACE_LEAD + NEC_SPACE_HOLDING) / 2, // markLeadThreshold, spaceLeadThreshold + (NEC_SPACE_HOLDING + NEC_SPACE_ONE) / 2, 0, // spaceLeadHoldingThreshold, markThreshold + (NEC_SPACE_ONE + NEC_SPACE_ZERO) / 2, // spaceThreshold + 0, 0>// markTimeout, spaceTimeout + (duration, data); + + if (newInput){ + // Check if the protcol's checksum is correct + bool holding; + if (IRLcheckInverse1(data) || (holding = IRLcheckHolding(data))){ + // normally NEC also check for the inverse of the address. + // newer remotes dont have this because of the wide used protocol all addresses were already used + // to make it less complicated its left out and the user can check the command inverse himself if needed + //if (!holding && !extended && !IRLcheckInverse0(data)) + // return; + + // save address + command and trigger event + uint16_t address = UINT16_AT_OFFSET(data, 0); + uint32_t command = UINT16_AT_OFFSET(data, 2); + IREvent(IR_NEC, address, command); + } + } +} + +template <bool extraAccuracy> void decodePanasonic(const uint16_t duration){ + // temporary buffer to hold bytes for decoding this protocol + static uint8_t data[PANASONIC_BLOCKS]; + + // pass the duration to the decoding function + bool newInput; + if (extraAccuracy) // no accuracy set at the moment, no conflict detected yet + newInput = IRLdecode <PANASONIC_LENGTH, (PANASONIC_TIMEOUT + PANASONIC_MARK_LEAD) / 2, // irLength, timeoutThreshold + (PANASONIC_MARK_LEAD + PANASONIC_SPACE_ONE) / 2, (PANASONIC_SPACE_LEAD + PANASONIC_SPACE_ONE) / 2, // markLeadThreshold, spaceLeadThreshold + 0, 0, // spaceLeadHoldingThreshold, markThreshold + (PANASONIC_SPACE_ONE + PANASONIC_SPACE_ZERO) / 2, // spaceThreshold + 0, 0>// markTimeout, spaceTimeout + (duration, data); + else + newInput = IRLdecode <PANASONIC_LENGTH, (PANASONIC_TIMEOUT + PANASONIC_MARK_LEAD) / 2, // irLength, timeoutThreshold + (PANASONIC_MARK_LEAD + PANASONIC_SPACE_ONE) / 2, (PANASONIC_SPACE_LEAD + PANASONIC_SPACE_ONE) / 2, // markLeadThreshold, spaceLeadThreshold + 0, 0, // spaceLeadHoldingThreshold, markThreshold + (PANASONIC_SPACE_ONE + PANASONIC_SPACE_ZERO) / 2, // spaceThreshold + 0, 0>// markTimeout, spaceTimeout + (duration, data); + + if (newInput){ + // Check if the protcol's checksum is correct + if (IRLcheckXOR0(data)){ + uint16_t address = UINT16_AT_OFFSET(data, 0); + uint32_t command = UINT32_AT_OFFSET(data, 2); IREvent(IR_PANASONIC, address, command); + return; + } + } +} + +template <bool extraAccuracy> void decodeSony12(const uint16_t duration){ + // temporary buffer to hold bytes for decoding this protocol + static uint8_t data[SONY_BLOCKS_12]; + + // pass the duration to the decoding function + bool newInput; + if (extraAccuracy) + newInput = IRLdecode <SONY_LENGTH_12, (SONY_TIMEOUT + SONY_MARK_LEAD) / 2, // irLength, timeoutThreshold + (SONY_MARK_LEAD + SONY_MARK_ONE) / 2, 0, // markLeadThreshold, spaceLeadThreshold + 0, (SONY_MARK_ONE + SONY_MARK_ZERO) / 2, // spaceLeadHoldingThreshold, markThreshold + 0, // spaceThreshold + (SONY_MARK_LEAD + SONY_MARK_ONE) / 2, SONY_MARK_ONE>// markTimeout, spaceTimeout + (duration, data); + else + newInput = IRLdecode <SONY_LENGTH_12, (SONY_TIMEOUT + SONY_MARK_LEAD) / 2, // irLength, timeoutThreshold + (SONY_MARK_LEAD + SONY_MARK_ONE) / 2, 0, // markLeadThreshold, spaceLeadThreshold + 0, (SONY_MARK_ONE + SONY_MARK_ZERO) / 2, // spaceLeadHoldingThreshold, markThreshold + 0, // spaceThreshold + 0, 0>// markTimeout, spaceTimeout + (duration, data); + + if (newInput){ + // protocol has no checksum + uint16_t address = UINT16_AT_OFFSET(data, 0) >> 7; + uint32_t command = data[0] & 0x7F; + IREvent(IR_SONY12, address, command); + return; + } +} + +void decodeRaw(const uint16_t duration){ + //TODO, use advanced raw example instead +} + +bool IRLcheckInverse0(uint8_t data[]){ + // check if byte 2 and is the inverse of byte 3 + if (uint8_t((data[0] ^ (~data[1]))) == 0) + return true; + else return false; +} + +bool IRLcheckInverse1(uint8_t data[]){ + // check if byte 0 and is the inverse of byte 1 + if (uint8_t((data[2] ^ (~data[3]))) == 0) + return true; + else return false; +} + +bool IRLcheckHolding(uint8_t data[]){ + // check if at least the command is always 1 + if (data[2] == 0xFF && data[3] == 0xFF) + return true; + else return false; +} + +bool IRLcheckXOR0(uint8_t data[]){ + // this function is used for panasonic checksum + if (uint8_t(data[2] ^ data[3] ^ data[4]) == data[5]) + return true; + else return false; +} + +// multifunctional template for receiving +template <uint8_t irLength, uint16_t timeoutThreshold, uint16_t markLeadThreshold, uint16_t spaceLeadThreshold, + uint16_t spaceLeadHoldingThreshold, uint16_t markThreshold, uint16_t spaceThreshold, + uint16_t markTimeout, uint16_t spaceTimeout> + bool IRLdecode(uint16_t duration, uint8_t data[]){ + + // variables for ir processing + static uint8_t count = 0; + + // if timeout always start next possible reading and abort any pending readings + if (duration >= timeoutThreshold) + count = 1; + + // on a reset (error in decoding) we are waiting for a timeout to start a new reading again + // this is to not conflict with other protocols while they are sending 0/1 which might be similar to a lead in another protocol + else if (count == 0) + return false; + + // check pulses for mark/space and lead + logical 0/1 seperate + else{ + // Mark pulses (odd numbers) + if (count % 2 == 1){ + // check Mark Lead (needs a timeout or a correct signal) + if (markLeadThreshold && count == 1){ + // lead is okay// wrong lead + if (duration <= markLeadThreshold){ + count = 0; + return false; + } + } + + else{ + // check for timeout if needed (might be a different protocol) + if (markTimeout && duration > markTimeout){ + count = 0; + return false; + } + + // only check values if the protocol has different logical space pulses + else if (markThreshold){ + + // get number of the Mark Bits (starting from zero) + uint8_t length; + // only save every 2nd value, substract the first two lead pulses + if (!spaceThreshold) + length = (count / 2) - 1; + // special case: spaces and marks both have data in the pulse + else length = count - 2; + + // move bits and write 1 or 0 depending on the duration + // 1.7: changed from MSB to LSB. somehow takes a bit more flash but is correct and easier to handle. + data[length / 8] >>= 1; + if (duration > markThreshold) + data[length / 8] |= 0x80; + //else // normally not needed through the bitshift + // data[length / 8] &= ~0x80; + } + + // check last input (always a mark) + if (count > irLength){ + count = 0; + return true; + } + } + } + + // Space pulses (even numbers) + else{ + //check Space Lead/Space Holding + if (spaceLeadThreshold && count == 2){ + // normal Space, next reading + if (duration > spaceLeadThreshold); + + // Button holding (if supported by protocol) + else if (spaceLeadHoldingThreshold && duration > spaceLeadHoldingThreshold){ + // set command to 0xFF if button is held down + if (irLength == (4 * 8 * 2 + 2)){ + data[0] = data[1] = 0x00; + data[2] = data[3] = 0xFF; + } + count = 0; + return true; + } + // wrong space + else { + count = 0; + return false; + } + } + else{ + // check for timeout if needed (might be a different protocol) + if (spaceTimeout && duration > spaceTimeout){ + count = 0; + return false; + } + + // only check values if the protocol has different logical space pulses + else if (spaceThreshold){ + + // get number of the Space Bits (starting from zero) + uint8_t length; + // only save every 2nd value, substract the first two lead pulses + if (!markThreshold) + length = (count / 2) - 2; + // special case: spaces and marks both have data in the pulse + else length = count - 2; + + // move bits and write 1 or 0 depending on the duration + // 1.7: changed from MSB to LSB. somehow takes a bit more flash but is correct and easier to handle. + data[length / 8] >>= 1; + if (duration > spaceThreshold) + data[length / 8] |= 0x80; + //else // normally not needed through the bitshift + // data[length / 8] &= ~0x80; + } + } + } + + // next reading, no errors + count++; + } + + // no valid input (yet) + return false; +} + +//================================================================================ +// Inline Implementations (send) +//================================================================================ + +template <IRType irType> +void IRLwrite(const uint8_t pin, uint16_t address, uint32_t command) +{ + // get the port mask and the pointers to the out/mode registers for faster access + uint8_t bitMask = digitalPinToBitMask(pin); + uint8_t port = digitalPinToPort(pin); + volatile uint8_t * outPort = portOutputRegister(port); + volatile uint8_t * modePort = portModeRegister(port); + + // set pin to OUTPUT and LOW + *modePort |= bitMask; + *outPort &= ~bitMask; + + // disable interrupts + uint8_t oldSREG = SREG; + cli(); + + switch (irType){ + + case IR_NEC: + // NEC only sends the data once + if (command == 0xFFF) + // send holding indicator + IRLsend<0, 0, NEC_HZ, 0, NEC_MARK_LEAD, NEC_SPACE_HOLDING, + 0, 0, 0, 0> + (outPort, bitMask, address, command); + else + // send data + IRLsend<NEC_ADDRESS_LENGTH, NEC_COMMAND_LENGTH, NEC_HZ, IR_ADDRESS_FIRST, NEC_MARK_LEAD, NEC_SPACE_LEAD, + NEC_MARK_ZERO, NEC_MARK_ONE, NEC_SPACE_ZERO, NEC_SPACE_ONE> + (outPort, bitMask, address, command); + break; + + case IR_PANASONIC: //TODO test + // send data + IRLsend<PANASONIC_ADDRESS_LENGTH, PANASONIC_COMMAND_LENGTH, PANASONIC_HZ, IR_ADDRESS_FIRST, PANASONIC_MARK_LEAD, PANASONIC_SPACE_LEAD, + PANASONIC_MARK_ZERO, PANASONIC_MARK_ONE, PANASONIC_SPACE_ZERO, PANASONIC_SPACE_ONE> + (outPort, bitMask, address, command); + break; + + case IR_SONY12: //TODO test, address -1? + // repeat 3 times + for (uint8_t i = 0; i < 3; i++) + // send data + IRLsend<SONY_ADDRESS_LENGTH_12, SONY_COMMAND_LENGTH_12, SONY_HZ, IR_COMMAND_FIRST, SONY_MARK_LEAD, SONY_SPACE_LEAD, + SONY_MARK_ZERO, SONY_MARK_ONE, SONY_SPACE_ZERO, SONY_SPACE_ONE> + (outPort, bitMask, address, command); + break; + } + + // enable interrupts + SREG = oldSREG; + + // set pin to INPUT again to be save + *modePort &= ~bitMask; +} + +// multifunctional template for sending +template <uint8_t addressLength, uint8_t commandLength, + uint16_t Hz, bool addressFirst, + uint16_t markLead, uint16_t spaceLead, + uint16_t markZero, uint16_t markOne, + uint16_t spaceZero, uint16_t spaceOne> + void IRLsend(volatile uint8_t * outPort, uint8_t bitmask, uint16_t address, uint32_t command){ + + // send lead mark + if (markLead) + IRLmark(Hz, outPort, bitmask, markLead); + + // send lead space + if (spaceLead) + IRLspace(outPort, bitmask, spaceLead); + + // abort if input values are both the same (sending a holding signal for example) + if (markOne != markZero || spaceOne != spaceZero) + { + // go through all bits + for (uint8_t i = 0; i < (addressLength + commandLength); i++){ + // determine if its a logical one or zero, starting with address or command + bool bitToSend; + if (addressFirst && i < addressLength || !addressFirst && i >= commandLength){ + bitToSend = address & 0x01; + address >>= 1; + } + else{ + bitToSend = command & 0x01; + command >>= 1; + } + + // send logic mark bits if needed + if (markOne != markZero){ + // modulate if spaces dont have logic, else only every even number + if (spaceOne == spaceZero || spaceOne != spaceZero && i % 2 == 0) + { + if (bitToSend) + IRLmark(Hz, outPort, bitmask, markOne); + else + IRLmark(Hz, outPort, bitmask, markZero); + } + } + else + IRLmark(Hz, outPort, bitmask, markOne); + + // send logic space bits if needed + if (spaceOne != spaceZero){ + // modulate if marks dont have logic, else only every odd number + if (markOne == markZero || markOne != markZero && i % 2 == 1){ + if (bitToSend) + IRLspace(outPort, bitmask, spaceOne); + else + IRLspace(outPort, bitmask, spaceZero); + } + } + else + IRLspace(outPort, bitmask, spaceOne); + } + } + + // finish mark + IRLmark(Hz, outPort, bitmask, markZero); //TODO zero or one for sony? + IRLspace(outPort, bitmask, 0); +} + +void IRLmark(const uint16_t Hz, volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) { + /* + Bitbangs PWM in the given Hz number for the given time + ________________________________________________________________________________ + Delay calculation: + F_CPU/1.000.000 to get number of cycles/uS + /3 to get the number of loops needed for 1ms (1loop = 3 cycles) + + Multiply with the number of ms delay: + 1/kHz to get the seconds + * 1.000.000 to get it in uS + /2 to get half of a full pulse + + Substract the while, portmanipulation, loop overhead /3 loop cycles + + F_CPU(16.000.000) 1 * 1.000.000(pulse in uS) 12(overhead) + ========================== * ========================== - ============== + 1.000.000 * 3(loop cycles) Hz * 2(half of a pulse) 3(loop cycles) + + <==> + + F_CPU(16.000.000) - (12(overhead) * Hz * 2(half of a pulse)) + =========================================================== + Hz * 2(half of a on/off pulse) * 3(loop cycles) + + ________________________________________________________________________________ + Iterations calculation: + Devide time with cycles in while loop + Multiply this with the cycles per uS + cycles per while loop: 3(loop cycles) * delay + overhead + + time * (F_CPU(16.000.000) / 1.000.000) + ====================================== + delay*3(loop cycles) + overhead + */ + + const uint32_t loopCycles = 3; + const uint32_t overHead = 12; // just a guess from try + error + uint8_t delay = (F_CPU - (overHead * Hz * 2UL)) / (Hz * 2UL * loopCycles); + uint16_t iterations = (time*(F_CPU / 1000000UL)) / (delay * loopCycles + overHead); + + while (iterations--){ + // flip pin state and wait for the calculated time + *outPort ^= bitMask; +#ifdef IRLREMOTE_AVR + _delay_loop_1(delay); +#else + // ARM TODO? +#endif + } +} + +void IRLspace(volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) { + // Sends an IRLspace for the specified number of microseconds. + // A IRLspace is no output, so the PWM output is disabled. + *outPort &= ~bitMask; // write pin LOW + delayMicroseconds(time); + //_delay_loop_2(time*(F_CPU/1000000UL)/4UL); +} + +#endif \ No newline at end of file
--- a/katka/creep.ino Sun Oct 12 10:54:09 2014 +0200 +++ b/katka/creep.ino Thu Jun 11 13:46:30 2015 +0200 @@ -1,4 +1,5 @@ #include "misc.h" +#include "ir.h" #include "clock.h" #include "servos.h" #include "leg.h" @@ -25,8 +26,8 @@ HOME_Y - 8 + creep_tilt * LEGS[leg][3]); } } - ir(); tick(TICK); + ir_loop(); } void creep() { @@ -38,27 +39,27 @@ return; } if (LEGS[leg][3] > 0) { - while (creep_tilt < 4) { + while (creep_tilt < 6) { creep_tilt += 2; creep_frame(); } } else { - while (creep_tilt > -4) { + while (creep_tilt > -6) { creep_tilt -= 2; creep_frame(); } } creep_on_ground[leg] = false; - move_leg_by(leg, 20, -20); + move_leg_by(leg, 20, -10); creep_frame(); creep_frame(); move_leg(leg, (HOME_X - 10) * LEGS[leg][2] + 15 + - (10 * creep_speed + creep_rotation * LEGS[leg][2]), + (8 * creep_speed + creep_rotation * LEGS[leg][2]), legs_y[leg]); creep_frame(); creep_frame(); - move_leg_by(leg, 0, 20); + move_leg_by(leg, 0, 10); creep_frame(); creep_frame(); creep_on_ground[leg] = true;
--- a/katka/ir.ino Sun Oct 12 10:54:09 2014 +0200 +++ b/katka/ir.ino Thu Jun 11 13:46:30 2015 +0200 @@ -1,37 +1,50 @@ #include "creep.h" void ir_setup() { - IRLbegin<IR_ALL>(0); // Sensor on PIN 2 + IRLbegin<IR_NEC>(0); // Sensor on PIN 2 pinMode(13, OUTPUT); digitalWrite(13, LOW); } -void ir() { - // digitalWrite(13, LOW); -} - -void IREvent(uint8_t protocol, uint16_t address, uint32_t command) { +void ir_loop() { static uint32_t last=0; + uint32_t IRcommand = 0; + static bool led = true; - if (command == 0xFFFFFF) { - command = last; + if (!IRLavailable()) { + if (led) { + digitalWrite(13, LOW); + led = false; + } + return; } - switch (command) { - case 0x02FD: + + if (IRcommand == 0xFFFF) { + IRcommand = last; + } else { + last = IRcommand; + } + + digitalWrite(13, HIGH); + led = true; + + switch (IRcommand) { + case 0xBF40: creep_speed = min(1.0, creep_speed + 0.25); break; - case 0x9867: + case 0xE619: creep_speed = max(-1.0, creep_speed - 0.25); break; - case 0xE01F: + case 0xF807: creep_rotation = min(1.0, creep_rotation + 0.25); break; - case 0x906F: + case 0xF609: creep_rotation = max(-1.0, creep_rotation - 0.25); break; - case 0xA857: + case 0xEA15: creep_speed = 0.0; creep_rotation = 0.0; break; } + IRLreset(); }
--- a/katka/katka.ino Sun Oct 12 10:54:09 2014 +0200 +++ b/katka/katka.ino Thu Jun 11 13:46:30 2015 +0200 @@ -1,6 +1,6 @@ /* Katka creeping around autonomously. */ -#include <IRLremote.h> +#include "IRLremote.h" #include <Servo.h> #include "servos.h"
--- a/katka/servos.ino Sun Oct 12 10:54:09 2014 +0200 +++ b/katka/servos.ino Thu Jun 11 13:46:30 2015 +0200 @@ -12,7 +12,7 @@ // pin, reverse, trim // hind right - {6, -1, 5}, // ankle + {6, -1, 0}, // ankle {7, 1, 0}, // knee // front right @@ -25,7 +25,7 @@ // hind left {12, -1, 0}, // knee - {14, 1, -5}, // ankle + {14, 1, 0}, // ankle }; Servo servos[MAX_SERVO]; @@ -47,5 +47,6 @@ void servo_setup() { for (unsigned char servo = 0; servo < MAX_SERVO; ++servo) { servos[servo].attach(SERVOS[servo][0], SERVO_FREQ_MIN, SERVO_FREQ_MAX); + delay(200); } }
