Infrared remote library for Arduino: send and receive infrared signals with multiple protocols Port from Arduino-IRremote https://github.com/z3t0/Arduino-IRremote
Dependents: mbed-os-example-FinalReal_copy
irPronto.cpp@8:9d9b1e1f9b1b, 2019-06-16 (annotated)
- Committer:
- eunmango
- Date:
- Sun Jun 16 04:49:45 2019 +0000
- Revision:
- 8:9d9b1e1f9b1b
- Parent:
- 0:70c8e56bac45
s
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yuhki50 | 0:70c8e56bac45 | 1 | #define TEST 0 |
yuhki50 | 0:70c8e56bac45 | 2 | |
yuhki50 | 0:70c8e56bac45 | 3 | #if TEST |
yuhki50 | 0:70c8e56bac45 | 4 | # define SEND_PRONTO 1 |
yuhki50 | 0:70c8e56bac45 | 5 | # define PRONTO_ONCE false |
yuhki50 | 0:70c8e56bac45 | 6 | # define PRONTO_REPEAT true |
yuhki50 | 0:70c8e56bac45 | 7 | # define PRONTO_FALLBACK true |
yuhki50 | 0:70c8e56bac45 | 8 | # define PRONTO_NOFALLBACK false |
yuhki50 | 0:70c8e56bac45 | 9 | #endif |
yuhki50 | 0:70c8e56bac45 | 10 | |
yuhki50 | 0:70c8e56bac45 | 11 | #if SEND_PRONTO |
yuhki50 | 0:70c8e56bac45 | 12 | |
yuhki50 | 0:70c8e56bac45 | 13 | //****************************************************************************** |
yuhki50 | 0:70c8e56bac45 | 14 | #if TEST |
yuhki50 | 0:70c8e56bac45 | 15 | # include <stdio.h> |
yuhki50 | 0:70c8e56bac45 | 16 | void enableIROut (int freq) { printf("\nFreq = %d KHz\n", freq); } |
yuhki50 | 0:70c8e56bac45 | 17 | void mark (int t) { printf("+%d," , t); } |
yuhki50 | 0:70c8e56bac45 | 18 | void space (int t) { printf("-%d, ", t); } |
yuhki50 | 0:70c8e56bac45 | 19 | #else |
yuhki50 | 0:70c8e56bac45 | 20 | # include "IRremote.h" |
yuhki50 | 0:70c8e56bac45 | 21 | #endif // TEST |
yuhki50 | 0:70c8e56bac45 | 22 | |
yuhki50 | 0:70c8e56bac45 | 23 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 24 | // Check for a valid hex digit |
yuhki50 | 0:70c8e56bac45 | 25 | // |
yuhki50 | 0:70c8e56bac45 | 26 | bool ishex (char ch) |
yuhki50 | 0:70c8e56bac45 | 27 | { |
yuhki50 | 0:70c8e56bac45 | 28 | return ( ((ch >= '0') && (ch <= '9')) || |
yuhki50 | 0:70c8e56bac45 | 29 | ((ch >= 'A') && (ch <= 'F')) || |
yuhki50 | 0:70c8e56bac45 | 30 | ((ch >= 'a') && (ch <= 'f')) ) ? true : false ; |
yuhki50 | 0:70c8e56bac45 | 31 | } |
yuhki50 | 0:70c8e56bac45 | 32 | |
yuhki50 | 0:70c8e56bac45 | 33 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 34 | // Check for a valid "blank" ... '\0' is a valid "blank" |
yuhki50 | 0:70c8e56bac45 | 35 | // |
yuhki50 | 0:70c8e56bac45 | 36 | bool isblank (char ch) |
yuhki50 | 0:70c8e56bac45 | 37 | { |
yuhki50 | 0:70c8e56bac45 | 38 | return ((ch == ' ') || (ch == '\t') || (ch == '\0')) ? true : false ; |
yuhki50 | 0:70c8e56bac45 | 39 | } |
yuhki50 | 0:70c8e56bac45 | 40 | |
yuhki50 | 0:70c8e56bac45 | 41 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 42 | // Bypass spaces |
yuhki50 | 0:70c8e56bac45 | 43 | // |
yuhki50 | 0:70c8e56bac45 | 44 | bool byp (char** pcp) |
yuhki50 | 0:70c8e56bac45 | 45 | { |
yuhki50 | 0:70c8e56bac45 | 46 | while (isblank(**pcp)) (*pcp)++ ; |
yuhki50 | 0:70c8e56bac45 | 47 | } |
yuhki50 | 0:70c8e56bac45 | 48 | |
yuhki50 | 0:70c8e56bac45 | 49 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 50 | // Hex-to-Byte : Decode a hex digit |
yuhki50 | 0:70c8e56bac45 | 51 | // We assume the character has already been validated |
yuhki50 | 0:70c8e56bac45 | 52 | // |
yuhki50 | 0:70c8e56bac45 | 53 | uint8_t htob (char ch) |
yuhki50 | 0:70c8e56bac45 | 54 | { |
yuhki50 | 0:70c8e56bac45 | 55 | if ((ch >= '0') && (ch <= '9')) return ch - '0' ; |
yuhki50 | 0:70c8e56bac45 | 56 | if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ; |
yuhki50 | 0:70c8e56bac45 | 57 | if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ; |
yuhki50 | 0:70c8e56bac45 | 58 | } |
yuhki50 | 0:70c8e56bac45 | 59 | |
yuhki50 | 0:70c8e56bac45 | 60 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 61 | // Hex-to-Word : Decode a block of 4 hex digits |
yuhki50 | 0:70c8e56bac45 | 62 | // We assume the string has already been validated |
yuhki50 | 0:70c8e56bac45 | 63 | // and the pointer being passed points at the start of a block of 4 hex digits |
yuhki50 | 0:70c8e56bac45 | 64 | // |
yuhki50 | 0:70c8e56bac45 | 65 | uint16_t htow (char* cp) |
yuhki50 | 0:70c8e56bac45 | 66 | { |
yuhki50 | 0:70c8e56bac45 | 67 | return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) | |
yuhki50 | 0:70c8e56bac45 | 68 | (htob(cp[2]) << 4) | (htob(cp[3]) ) ) ; |
yuhki50 | 0:70c8e56bac45 | 69 | } |
yuhki50 | 0:70c8e56bac45 | 70 | |
yuhki50 | 0:70c8e56bac45 | 71 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 72 | // |
yuhki50 | 0:70c8e56bac45 | 73 | bool sendPronto (char* s, bool repeat, bool fallback) |
yuhki50 | 0:70c8e56bac45 | 74 | { |
yuhki50 | 0:70c8e56bac45 | 75 | int i; |
yuhki50 | 0:70c8e56bac45 | 76 | int len; |
yuhki50 | 0:70c8e56bac45 | 77 | int skip; |
yuhki50 | 0:70c8e56bac45 | 78 | char* cp; |
yuhki50 | 0:70c8e56bac45 | 79 | uint16_t freq; // Frequency in KHz |
yuhki50 | 0:70c8e56bac45 | 80 | uint8_t usec; // pronto uSec/tick |
yuhki50 | 0:70c8e56bac45 | 81 | uint8_t once; |
yuhki50 | 0:70c8e56bac45 | 82 | uint8_t rpt; |
yuhki50 | 0:70c8e56bac45 | 83 | |
yuhki50 | 0:70c8e56bac45 | 84 | // Validate the string |
yuhki50 | 0:70c8e56bac45 | 85 | for (cp = s; *cp; cp += 4) { |
yuhki50 | 0:70c8e56bac45 | 86 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 87 | if ( !ishex(cp[0]) || !ishex(cp[1]) || |
yuhki50 | 0:70c8e56bac45 | 88 | !ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ; |
yuhki50 | 0:70c8e56bac45 | 89 | } |
yuhki50 | 0:70c8e56bac45 | 90 | |
yuhki50 | 0:70c8e56bac45 | 91 | // We will use cp to traverse the string |
yuhki50 | 0:70c8e56bac45 | 92 | cp = s; |
yuhki50 | 0:70c8e56bac45 | 93 | |
yuhki50 | 0:70c8e56bac45 | 94 | // Check mode = Oscillated/Learned |
yuhki50 | 0:70c8e56bac45 | 95 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 96 | if (htow(cp) != 0000) return false; |
yuhki50 | 0:70c8e56bac45 | 97 | cp += 4; |
yuhki50 | 0:70c8e56bac45 | 98 | |
yuhki50 | 0:70c8e56bac45 | 99 | // Extract & set frequency |
yuhki50 | 0:70c8e56bac45 | 100 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 101 | freq = (int)(1000000 / (htow(cp) * 0.241246)); // Rounding errors will occur, tolerance is +/- 10% |
yuhki50 | 0:70c8e56bac45 | 102 | usec = (int)(((1.0 / freq) * 1000000) + 0.5); // Another rounding error, thank Cod for analogue electronics |
yuhki50 | 0:70c8e56bac45 | 103 | freq /= 1000; // This will introduce a(nother) rounding error which we do not want in the usec calcualtion |
yuhki50 | 0:70c8e56bac45 | 104 | cp += 4; |
yuhki50 | 0:70c8e56bac45 | 105 | |
yuhki50 | 0:70c8e56bac45 | 106 | // Get length of "once" code |
yuhki50 | 0:70c8e56bac45 | 107 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 108 | once = htow(cp); |
yuhki50 | 0:70c8e56bac45 | 109 | cp += 4; |
yuhki50 | 0:70c8e56bac45 | 110 | |
yuhki50 | 0:70c8e56bac45 | 111 | // Get length of "repeat" code |
yuhki50 | 0:70c8e56bac45 | 112 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 113 | rpt = htow(cp); |
yuhki50 | 0:70c8e56bac45 | 114 | cp += 4; |
yuhki50 | 0:70c8e56bac45 | 115 | |
yuhki50 | 0:70c8e56bac45 | 116 | // Which code are we sending? |
yuhki50 | 0:70c8e56bac45 | 117 | if (fallback) { // fallback on the "other" code if "this" code is not present |
yuhki50 | 0:70c8e56bac45 | 118 | if (!repeat) { // requested 'once' |
yuhki50 | 0:70c8e56bac45 | 119 | if (once) len = once * 2, skip = 0 ; // if once exists send it |
yuhki50 | 0:70c8e56bac45 | 120 | else len = rpt * 2, skip = 0 ; // else send repeat code |
yuhki50 | 0:70c8e56bac45 | 121 | } else { // requested 'repeat' |
yuhki50 | 0:70c8e56bac45 | 122 | if (rpt) len = rpt * 2, skip = 0 ; // if rpt exists send it |
yuhki50 | 0:70c8e56bac45 | 123 | else len = once * 2, skip = 0 ; // else send once code |
yuhki50 | 0:70c8e56bac45 | 124 | } |
yuhki50 | 0:70c8e56bac45 | 125 | } else { // Send what we asked for, do not fallback if the code is empty! |
yuhki50 | 0:70c8e56bac45 | 126 | if (!repeat) len = once * 2, skip = 0 ; // 'once' starts at 0 |
yuhki50 | 0:70c8e56bac45 | 127 | else len = rpt * 2, skip = once ; // 'repeat' starts where 'once' ends |
yuhki50 | 0:70c8e56bac45 | 128 | } |
yuhki50 | 0:70c8e56bac45 | 129 | |
yuhki50 | 0:70c8e56bac45 | 130 | // Skip to start of code |
yuhki50 | 0:70c8e56bac45 | 131 | for (i = 0; i < skip; i++, cp += 4) byp(&cp) ; |
yuhki50 | 0:70c8e56bac45 | 132 | |
yuhki50 | 0:70c8e56bac45 | 133 | // Send code |
yuhki50 | 0:70c8e56bac45 | 134 | enableIROut(freq); |
yuhki50 | 0:70c8e56bac45 | 135 | for (i = 0; i < len; i++) { |
yuhki50 | 0:70c8e56bac45 | 136 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 137 | if (i & 1) space(htow(cp) * usec); |
yuhki50 | 0:70c8e56bac45 | 138 | else mark (htow(cp) * usec); |
yuhki50 | 0:70c8e56bac45 | 139 | cp += 4; |
yuhki50 | 0:70c8e56bac45 | 140 | } |
yuhki50 | 0:70c8e56bac45 | 141 | } |
yuhki50 | 0:70c8e56bac45 | 142 | |
yuhki50 | 0:70c8e56bac45 | 143 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 144 | #if TEST |
yuhki50 | 0:70c8e56bac45 | 145 | |
yuhki50 | 0:70c8e56bac45 | 146 | int main ( ) |
yuhki50 | 0:70c8e56bac45 | 147 | { |
yuhki50 | 0:70c8e56bac45 | 148 | char prontoTest[] = |
yuhki50 | 0:70c8e56bac45 | 149 | "0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10 |
yuhki50 | 0:70c8e56bac45 | 150 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20 |
yuhki50 | 0:70c8e56bac45 | 151 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30 |
yuhki50 | 0:70c8e56bac45 | 152 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40 |
yuhki50 | 0:70c8e56bac45 | 153 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50 |
yuhki50 | 0:70c8e56bac45 | 154 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60 |
yuhki50 | 0:70c8e56bac45 | 155 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70 |
yuhki50 | 0:70c8e56bac45 | 156 | "0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80 |
yuhki50 | 0:70c8e56bac45 | 157 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90 |
yuhki50 | 0:70c8e56bac45 | 158 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100 |
yuhki50 | 0:70c8e56bac45 | 159 | "0010 0030 0010 0aa6"; // 104 |
yuhki50 | 0:70c8e56bac45 | 160 | |
yuhki50 | 0:70c8e56bac45 | 161 | sendPronto(prontoTest, PRONTO_ONCE, PRONTO_FALLBACK); // once code |
yuhki50 | 0:70c8e56bac45 | 162 | sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_FALLBACK); // repeat code |
yuhki50 | 0:70c8e56bac45 | 163 | sendPronto(prontoTest, PRONTO_ONCE, PRONTO_NOFALLBACK); // once code |
yuhki50 | 0:70c8e56bac45 | 164 | sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_NOFALLBACK); // repeat code |
yuhki50 | 0:70c8e56bac45 | 165 | |
yuhki50 | 0:70c8e56bac45 | 166 | return 0; |
yuhki50 | 0:70c8e56bac45 | 167 | } |
yuhki50 | 0:70c8e56bac45 | 168 | |
yuhki50 | 0:70c8e56bac45 | 169 | #endif // TEST |
yuhki50 | 0:70c8e56bac45 | 170 | |
yuhki50 | 0:70c8e56bac45 | 171 | #endif // SEND_PRONTO |
yuhki50 | 0:70c8e56bac45 | 172 | |
yuhki50 | 0:70c8e56bac45 | 173 | |
yuhki50 | 0:70c8e56bac45 | 174 | |
yuhki50 | 0:70c8e56bac45 | 175 | |
yuhki50 | 0:70c8e56bac45 | 176 | |
yuhki50 | 0:70c8e56bac45 | 177 | |
yuhki50 | 0:70c8e56bac45 | 178 | |
yuhki50 | 0:70c8e56bac45 | 179 | |
yuhki50 | 0:70c8e56bac45 | 180 | |
yuhki50 | 0:70c8e56bac45 | 181 | |
yuhki50 | 0:70c8e56bac45 | 182 | |
yuhki50 | 0:70c8e56bac45 | 183 | |
yuhki50 | 0:70c8e56bac45 | 184 | |
yuhki50 | 0:70c8e56bac45 | 185 | |
yuhki50 | 0:70c8e56bac45 | 186 | |
yuhki50 | 0:70c8e56bac45 | 187 | |
yuhki50 | 0:70c8e56bac45 | 188 | |
yuhki50 | 0:70c8e56bac45 | 189 | |
yuhki50 | 0:70c8e56bac45 | 190 | |
yuhki50 | 0:70c8e56bac45 | 191 | |
yuhki50 | 0:70c8e56bac45 | 192 | |
yuhki50 | 0:70c8e56bac45 | 193 | |
yuhki50 | 0:70c8e56bac45 | 194 | |
yuhki50 | 0:70c8e56bac45 | 195 | |
yuhki50 | 0:70c8e56bac45 | 196 | |
yuhki50 | 0:70c8e56bac45 | 197 | |
yuhki50 | 0:70c8e56bac45 | 198 | |
yuhki50 | 0:70c8e56bac45 | 199 | |
yuhki50 | 0:70c8e56bac45 | 200 | |
yuhki50 | 0:70c8e56bac45 | 201 | |
yuhki50 | 0:70c8e56bac45 | 202 | |
yuhki50 | 0:70c8e56bac45 | 203 | |
yuhki50 | 0:70c8e56bac45 | 204 | |
yuhki50 | 0:70c8e56bac45 | 205 | |
yuhki50 | 0:70c8e56bac45 | 206 | |
yuhki50 | 0:70c8e56bac45 | 207 | |
yuhki50 | 0:70c8e56bac45 | 208 | |
yuhki50 | 0:70c8e56bac45 | 209 | |
yuhki50 | 0:70c8e56bac45 | 210 | |
yuhki50 | 0:70c8e56bac45 | 211 | |
yuhki50 | 0:70c8e56bac45 | 212 | |
yuhki50 | 0:70c8e56bac45 | 213 | |
yuhki50 | 0:70c8e56bac45 | 214 | |
yuhki50 | 0:70c8e56bac45 | 215 | |
yuhki50 | 0:70c8e56bac45 | 216 | |
yuhki50 | 0:70c8e56bac45 | 217 | |
yuhki50 | 0:70c8e56bac45 | 218 | |
yuhki50 | 0:70c8e56bac45 | 219 | |
yuhki50 | 0:70c8e56bac45 | 220 | |
yuhki50 | 0:70c8e56bac45 | 221 | |
yuhki50 | 0:70c8e56bac45 | 222 | |
yuhki50 | 0:70c8e56bac45 | 223 | |
yuhki50 | 0:70c8e56bac45 | 224 | |
yuhki50 | 0:70c8e56bac45 | 225 | |
yuhki50 | 0:70c8e56bac45 | 226 | |
yuhki50 | 0:70c8e56bac45 | 227 | |
yuhki50 | 0:70c8e56bac45 | 228 | |
yuhki50 | 0:70c8e56bac45 | 229 | |
yuhki50 | 0:70c8e56bac45 | 230 | #if 0 |
yuhki50 | 0:70c8e56bac45 | 231 | //****************************************************************************** |
yuhki50 | 0:70c8e56bac45 | 232 | // Sources: |
yuhki50 | 0:70c8e56bac45 | 233 | // http://www.remotecentral.com/features/irdisp2.htm |
yuhki50 | 0:70c8e56bac45 | 234 | // http://www.hifi-remote.com/wiki/index.php?title=Working_With_Pronto_Hex |
yuhki50 | 0:70c8e56bac45 | 235 | //****************************************************************************** |
yuhki50 | 0:70c8e56bac45 | 236 | |
yuhki50 | 0:70c8e56bac45 | 237 | #include <stdint.h> |
yuhki50 | 0:70c8e56bac45 | 238 | #include <stdio.h> |
yuhki50 | 0:70c8e56bac45 | 239 | |
yuhki50 | 0:70c8e56bac45 | 240 | #define IRPRONTO |
yuhki50 | 0:70c8e56bac45 | 241 | #include "IRremoteInt.h" // The Arduino IRremote library defines USECPERTICK |
yuhki50 | 0:70c8e56bac45 | 242 | |
yuhki50 | 0:70c8e56bac45 | 243 | //------------------------------------------------------------------------------ |
yuhki50 | 0:70c8e56bac45 | 244 | // Source: https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet |
yuhki50 | 0:70c8e56bac45 | 245 | // -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls |
yuhki50 | 0:70c8e56bac45 | 246 | // |
yuhki50 | 0:70c8e56bac45 | 247 | char prontoTest[] = |
yuhki50 | 0:70c8e56bac45 | 248 | "0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10 |
yuhki50 | 0:70c8e56bac45 | 249 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20 |
yuhki50 | 0:70c8e56bac45 | 250 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30 |
yuhki50 | 0:70c8e56bac45 | 251 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40 |
yuhki50 | 0:70c8e56bac45 | 252 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50 |
yuhki50 | 0:70c8e56bac45 | 253 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60 |
yuhki50 | 0:70c8e56bac45 | 254 | "0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70 |
yuhki50 | 0:70c8e56bac45 | 255 | "0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80 |
yuhki50 | 0:70c8e56bac45 | 256 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90 |
yuhki50 | 0:70c8e56bac45 | 257 | "0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100 |
yuhki50 | 0:70c8e56bac45 | 258 | "0010 0030 0010 0aa6"; // 104 |
yuhki50 | 0:70c8e56bac45 | 259 | |
yuhki50 | 0:70c8e56bac45 | 260 | //------------------------------------------------------------------------------ |
yuhki50 | 0:70c8e56bac45 | 261 | // This is the longest code we can support |
yuhki50 | 0:70c8e56bac45 | 262 | #define CODEMAX 200 |
yuhki50 | 0:70c8e56bac45 | 263 | |
yuhki50 | 0:70c8e56bac45 | 264 | //------------------------------------------------------------------------------ |
yuhki50 | 0:70c8e56bac45 | 265 | // This is the data we pull out of the pronto code |
yuhki50 | 0:70c8e56bac45 | 266 | typedef |
yuhki50 | 0:70c8e56bac45 | 267 | struct { |
yuhki50 | 0:70c8e56bac45 | 268 | int freq; // Carrier frequency (in Hz) |
yuhki50 | 0:70c8e56bac45 | 269 | int usec; // uSec per tick (based on freq) |
yuhki50 | 0:70c8e56bac45 | 270 | |
yuhki50 | 0:70c8e56bac45 | 271 | int codeLen; // Length of code |
yuhki50 | 0:70c8e56bac45 | 272 | uint16_t code[CODEMAX]; // Code in hex |
yuhki50 | 0:70c8e56bac45 | 273 | |
yuhki50 | 0:70c8e56bac45 | 274 | int onceLen; // Length of "once" transmit |
yuhki50 | 0:70c8e56bac45 | 275 | uint16_t* once; // Pointer to start within 'code' |
yuhki50 | 0:70c8e56bac45 | 276 | |
yuhki50 | 0:70c8e56bac45 | 277 | int rptLen; // Length of "repeat" transmit |
yuhki50 | 0:70c8e56bac45 | 278 | uint16_t* rpt; // Pointer to start within 'code' |
yuhki50 | 0:70c8e56bac45 | 279 | } |
yuhki50 | 0:70c8e56bac45 | 280 | pronto_t; |
yuhki50 | 0:70c8e56bac45 | 281 | |
yuhki50 | 0:70c8e56bac45 | 282 | //------------------------------------------------------------------------------ |
yuhki50 | 0:70c8e56bac45 | 283 | // From what I have seen, the only time we go over 8-bits is the 'space' |
yuhki50 | 0:70c8e56bac45 | 284 | // on the end which creates the lead-out/inter-code gap. Assuming I'm right, |
yuhki50 | 0:70c8e56bac45 | 285 | // we can code this up as a special case and otherwise halve the size of our |
yuhki50 | 0:70c8e56bac45 | 286 | // data! |
yuhki50 | 0:70c8e56bac45 | 287 | // Ignoring the first four values (the config data) and the last value |
yuhki50 | 0:70c8e56bac45 | 288 | // (the lead-out), if you find a protocol that uses values greater than 00fe |
yuhki50 | 0:70c8e56bac45 | 289 | // we are going to have to revisit this code! |
yuhki50 | 0:70c8e56bac45 | 290 | // |
yuhki50 | 0:70c8e56bac45 | 291 | // |
yuhki50 | 0:70c8e56bac45 | 292 | // So, the 0th byte will be the carrier frequency in Khz (NOT Hz) |
yuhki50 | 0:70c8e56bac45 | 293 | // " 1st " " " " length of the "once" code |
yuhki50 | 0:70c8e56bac45 | 294 | // " 2nd " " " " length of the "repeat" code |
yuhki50 | 0:70c8e56bac45 | 295 | // |
yuhki50 | 0:70c8e56bac45 | 296 | // Thereafter, odd bytes will be Mark lengths as a multiple of USECPERTICK uS |
yuhki50 | 0:70c8e56bac45 | 297 | // even " " " Space " " " " " " " |
yuhki50 | 0:70c8e56bac45 | 298 | // |
yuhki50 | 0:70c8e56bac45 | 299 | // Any occurence of "FF" in either a Mark or a Space will indicate |
yuhki50 | 0:70c8e56bac45 | 300 | // "Use the 16-bit FF value" which will also be a multiple of USECPERTICK uS |
yuhki50 | 0:70c8e56bac45 | 301 | // |
yuhki50 | 0:70c8e56bac45 | 302 | // |
yuhki50 | 0:70c8e56bac45 | 303 | // As a point of comparison, the test code (prontoTest[]) is 520 bytes |
yuhki50 | 0:70c8e56bac45 | 304 | // (yes, more than 0.5KB of our Arduino's precious 32KB) ... after conversion |
yuhki50 | 0:70c8e56bac45 | 305 | // to pronto hex that goes down to ((520/5)*2) = 208 bytes ... once converted to |
yuhki50 | 0:70c8e56bac45 | 306 | // our format we are down to ((208/2) -1 -1 +2) = 104 bytes |
yuhki50 | 0:70c8e56bac45 | 307 | // |
yuhki50 | 0:70c8e56bac45 | 308 | // In fariness this is still very memory-hungry |
yuhki50 | 0:70c8e56bac45 | 309 | // ...As a rough guide: |
yuhki50 | 0:70c8e56bac45 | 310 | // 10 codes cost 1K of memory (this will vary depending on the protocol). |
yuhki50 | 0:70c8e56bac45 | 311 | // |
yuhki50 | 0:70c8e56bac45 | 312 | // So if you're building a complex remote control, you will probably need to |
yuhki50 | 0:70c8e56bac45 | 313 | // keep the codes on an external memory device (not in the Arduino sketch) and |
yuhki50 | 0:70c8e56bac45 | 314 | // load them as you need them. Hmmm. |
yuhki50 | 0:70c8e56bac45 | 315 | // |
yuhki50 | 0:70c8e56bac45 | 316 | // This dictates that "Oscillated Pronto Codes" are probably NOT the way forward |
yuhki50 | 0:70c8e56bac45 | 317 | // |
yuhki50 | 0:70c8e56bac45 | 318 | // For example, prontoTest[] happens to be: A 48-bit IR code in Denon format |
yuhki50 | 0:70c8e56bac45 | 319 | // So we know it starts with 80/40 (Denon header) |
yuhki50 | 0:70c8e56bac45 | 320 | // and ends with 10/aa6 (Denon leadout) |
yuhki50 | 0:70c8e56bac45 | 321 | // and all (48) bits in between are either 10/10 (Denon 0) |
yuhki50 | 0:70c8e56bac45 | 322 | // or 10/30 (Denon 1) |
yuhki50 | 0:70c8e56bac45 | 323 | // So we could easily store this data in 1-byte ("Denon") |
yuhki50 | 0:70c8e56bac45 | 324 | // + 1-byte (Length=48) |
yuhki50 | 0:70c8e56bac45 | 325 | // + 6-bytes (IR code) |
yuhki50 | 0:70c8e56bac45 | 326 | // At 8-bytes per code, we can store 128 codes in 1KB or memory - that's a lot |
yuhki50 | 0:70c8e56bac45 | 327 | // better than the 2 (two) we started off with! |
yuhki50 | 0:70c8e56bac45 | 328 | // |
yuhki50 | 0:70c8e56bac45 | 329 | // And serendipitously, by reducing the amount of data, our program will run |
yuhki50 | 0:70c8e56bac45 | 330 | // a LOT faster! |
yuhki50 | 0:70c8e56bac45 | 331 | // |
yuhki50 | 0:70c8e56bac45 | 332 | // Again, I repeat, even after you have spent time converting the "Oscillated |
yuhki50 | 0:70c8e56bac45 | 333 | // Pronto Codes" in to IRremote format, it will be a LOT more memory-hungry |
yuhki50 | 0:70c8e56bac45 | 334 | // than using sendDenon() (or whichever) ...BUT these codes are easily |
yuhki50 | 0:70c8e56bac45 | 335 | // available on the internet, so we'll support them! |
yuhki50 | 0:70c8e56bac45 | 336 | // |
yuhki50 | 0:70c8e56bac45 | 337 | typedef |
yuhki50 | 0:70c8e56bac45 | 338 | struct { |
yuhki50 | 0:70c8e56bac45 | 339 | uint16_t FF; |
yuhki50 | 0:70c8e56bac45 | 340 | uint8_t code[CODEMAX]; |
yuhki50 | 0:70c8e56bac45 | 341 | } |
yuhki50 | 0:70c8e56bac45 | 342 | irCode_t; |
yuhki50 | 0:70c8e56bac45 | 343 | |
yuhki50 | 0:70c8e56bac45 | 344 | //------------------------------------------------------------------------------ |
yuhki50 | 0:70c8e56bac45 | 345 | #define DEBUGF(...) printf(__VA_ARGS__) |
yuhki50 | 0:70c8e56bac45 | 346 | |
yuhki50 | 0:70c8e56bac45 | 347 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 348 | // String must be block of 4 hex digits separated with blanks |
yuhki50 | 0:70c8e56bac45 | 349 | // |
yuhki50 | 0:70c8e56bac45 | 350 | bool validate (char* cp, int* len) |
yuhki50 | 0:70c8e56bac45 | 351 | { |
yuhki50 | 0:70c8e56bac45 | 352 | for (*len = 0; *cp; (*len)++, cp += 4) { |
yuhki50 | 0:70c8e56bac45 | 353 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 354 | if ( !ishex(cp[0]) || !ishex(cp[1]) || |
yuhki50 | 0:70c8e56bac45 | 355 | !ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ; |
yuhki50 | 0:70c8e56bac45 | 356 | } |
yuhki50 | 0:70c8e56bac45 | 357 | |
yuhki50 | 0:70c8e56bac45 | 358 | return true; |
yuhki50 | 0:70c8e56bac45 | 359 | } |
yuhki50 | 0:70c8e56bac45 | 360 | |
yuhki50 | 0:70c8e56bac45 | 361 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 362 | // Hex-to-Byte : Decode a hex digit |
yuhki50 | 0:70c8e56bac45 | 363 | // We assume the character has already been validated |
yuhki50 | 0:70c8e56bac45 | 364 | // |
yuhki50 | 0:70c8e56bac45 | 365 | uint8_t htob (char ch) |
yuhki50 | 0:70c8e56bac45 | 366 | { |
yuhki50 | 0:70c8e56bac45 | 367 | if ((ch >= '0') && (ch <= '9')) return ch - '0' ; |
yuhki50 | 0:70c8e56bac45 | 368 | if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ; |
yuhki50 | 0:70c8e56bac45 | 369 | if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ; |
yuhki50 | 0:70c8e56bac45 | 370 | } |
yuhki50 | 0:70c8e56bac45 | 371 | |
yuhki50 | 0:70c8e56bac45 | 372 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 373 | // Hex-to-Word : Decode a block of 4 hex digits |
yuhki50 | 0:70c8e56bac45 | 374 | // We assume the string has already been validated |
yuhki50 | 0:70c8e56bac45 | 375 | // and the pointer being passed points at the start of a block of 4 hex digits |
yuhki50 | 0:70c8e56bac45 | 376 | // |
yuhki50 | 0:70c8e56bac45 | 377 | uint16_t htow (char* cp) |
yuhki50 | 0:70c8e56bac45 | 378 | { |
yuhki50 | 0:70c8e56bac45 | 379 | return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) | |
yuhki50 | 0:70c8e56bac45 | 380 | (htob(cp[2]) << 4) | (htob(cp[3]) ) ) ; |
yuhki50 | 0:70c8e56bac45 | 381 | } |
yuhki50 | 0:70c8e56bac45 | 382 | |
yuhki50 | 0:70c8e56bac45 | 383 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 384 | // Convert the pronto string in to data |
yuhki50 | 0:70c8e56bac45 | 385 | // |
yuhki50 | 0:70c8e56bac45 | 386 | bool decode (char* s, pronto_t* p, irCode_t* ir) |
yuhki50 | 0:70c8e56bac45 | 387 | { |
yuhki50 | 0:70c8e56bac45 | 388 | int i, len; |
yuhki50 | 0:70c8e56bac45 | 389 | char* cp; |
yuhki50 | 0:70c8e56bac45 | 390 | |
yuhki50 | 0:70c8e56bac45 | 391 | // Validate the Pronto string |
yuhki50 | 0:70c8e56bac45 | 392 | if (!validate(s, &p->codeLen)) { |
yuhki50 | 0:70c8e56bac45 | 393 | DEBUGF("Invalid pronto string\n"); |
yuhki50 | 0:70c8e56bac45 | 394 | return false ; |
yuhki50 | 0:70c8e56bac45 | 395 | } |
yuhki50 | 0:70c8e56bac45 | 396 | DEBUGF("Found %d hex codes\n", p->codeLen); |
yuhki50 | 0:70c8e56bac45 | 397 | |
yuhki50 | 0:70c8e56bac45 | 398 | // Allocate memory to store the decoded string |
yuhki50 | 0:70c8e56bac45 | 399 | //if (!(p->code = malloc(p->len))) { |
yuhki50 | 0:70c8e56bac45 | 400 | // DEBUGF("Memory allocation failed\n"); |
yuhki50 | 0:70c8e56bac45 | 401 | // return false ; |
yuhki50 | 0:70c8e56bac45 | 402 | //} |
yuhki50 | 0:70c8e56bac45 | 403 | |
yuhki50 | 0:70c8e56bac45 | 404 | // Check in case our code is too long |
yuhki50 | 0:70c8e56bac45 | 405 | if (p->codeLen > CODEMAX) { |
yuhki50 | 0:70c8e56bac45 | 406 | DEBUGF("Code too long, edit CODEMAX and recompile\n"); |
yuhki50 | 0:70c8e56bac45 | 407 | return false ; |
yuhki50 | 0:70c8e56bac45 | 408 | } |
yuhki50 | 0:70c8e56bac45 | 409 | |
yuhki50 | 0:70c8e56bac45 | 410 | // Decode the string |
yuhki50 | 0:70c8e56bac45 | 411 | cp = s; |
yuhki50 | 0:70c8e56bac45 | 412 | for (i = 0; i < p->codeLen; i++, cp += 4) { |
yuhki50 | 0:70c8e56bac45 | 413 | byp(&cp); |
yuhki50 | 0:70c8e56bac45 | 414 | p->code[i] = htow(cp); |
yuhki50 | 0:70c8e56bac45 | 415 | } |
yuhki50 | 0:70c8e56bac45 | 416 | |
yuhki50 | 0:70c8e56bac45 | 417 | // Announce our findings |
yuhki50 | 0:70c8e56bac45 | 418 | DEBUGF("Input: |%s|\n", s); |
yuhki50 | 0:70c8e56bac45 | 419 | DEBUGF("Found: |"); |
yuhki50 | 0:70c8e56bac45 | 420 | for (i = 0; i < p->codeLen; i++) DEBUGF("%04x ", p->code[i]) ; |
yuhki50 | 0:70c8e56bac45 | 421 | DEBUGF("|\n"); |
yuhki50 | 0:70c8e56bac45 | 422 | |
yuhki50 | 0:70c8e56bac45 | 423 | DEBUGF("Form [%04X] : ", p->code[0]); |
yuhki50 | 0:70c8e56bac45 | 424 | if (p->code[0] == 0x0000) DEBUGF("Oscillated (Learned)\n"); |
yuhki50 | 0:70c8e56bac45 | 425 | else if (p->code[0] == 0x0100) DEBUGF("Unmodulated\n"); |
yuhki50 | 0:70c8e56bac45 | 426 | else DEBUGF("Unknown\n"); |
yuhki50 | 0:70c8e56bac45 | 427 | if (p->code[0] != 0x0000) return false ; // Can only handle Oscillated |
yuhki50 | 0:70c8e56bac45 | 428 | |
yuhki50 | 0:70c8e56bac45 | 429 | // Calculate the carrier frequency (+/- 10%) & uSecs per pulse |
yuhki50 | 0:70c8e56bac45 | 430 | // Pronto uses a crystal which generates a timeabse of 0.241246 |
yuhki50 | 0:70c8e56bac45 | 431 | p->freq = (int)(1000000 / (p->code[1] * 0.241246)); |
yuhki50 | 0:70c8e56bac45 | 432 | p->usec = (int)(((1.0 / p->freq) * 1000000) + 0.5); |
yuhki50 | 0:70c8e56bac45 | 433 | ir->code[0] = p->freq / 1000; |
yuhki50 | 0:70c8e56bac45 | 434 | DEBUGF("Freq [%04X] : %d Hz (%d uS/pluse) -> %d KHz\n", |
yuhki50 | 0:70c8e56bac45 | 435 | p->code[1], p->freq, p->usec, ir->code[0]); |
yuhki50 | 0:70c8e56bac45 | 436 | |
yuhki50 | 0:70c8e56bac45 | 437 | // Set the length & start pointer for the "once" code |
yuhki50 | 0:70c8e56bac45 | 438 | p->onceLen = p->code[2]; |
yuhki50 | 0:70c8e56bac45 | 439 | p->once = &p->code[4]; |
yuhki50 | 0:70c8e56bac45 | 440 | ir->code[1] = p->onceLen; |
yuhki50 | 0:70c8e56bac45 | 441 | DEBUGF("Once [%04X] : %d\n", p->code[2], p->onceLen); |
yuhki50 | 0:70c8e56bac45 | 442 | |
yuhki50 | 0:70c8e56bac45 | 443 | // Set the length & start pointer for the "repeat" code |
yuhki50 | 0:70c8e56bac45 | 444 | p->rptLen = p->code[3]; |
yuhki50 | 0:70c8e56bac45 | 445 | p->rpt = &p->code[4 + p->onceLen]; |
yuhki50 | 0:70c8e56bac45 | 446 | ir->code[2] = p->rptLen; |
yuhki50 | 0:70c8e56bac45 | 447 | DEBUGF("Rpt [%04X] : %d\n", p->code[3], p->rptLen); |
yuhki50 | 0:70c8e56bac45 | 448 | |
yuhki50 | 0:70c8e56bac45 | 449 | // Check everything tallies |
yuhki50 | 0:70c8e56bac45 | 450 | if (1 + 1 + 1 + 1 + (p->onceLen * 2) + (p->rptLen * 2) != p->codeLen) { |
yuhki50 | 0:70c8e56bac45 | 451 | DEBUGF("Bad code length\n"); |
yuhki50 | 0:70c8e56bac45 | 452 | return false; |
yuhki50 | 0:70c8e56bac45 | 453 | } |
yuhki50 | 0:70c8e56bac45 | 454 | |
yuhki50 | 0:70c8e56bac45 | 455 | // Convert the IR data to our new format |
yuhki50 | 0:70c8e56bac45 | 456 | ir->FF = p->code[p->codeLen - 1]; |
yuhki50 | 0:70c8e56bac45 | 457 | |
yuhki50 | 0:70c8e56bac45 | 458 | len = (p->onceLen * 2) + (p->rptLen * 2); |
yuhki50 | 0:70c8e56bac45 | 459 | DEBUGF("Encoded: |"); |
yuhki50 | 0:70c8e56bac45 | 460 | for (i = 0; i < len; i++) { |
yuhki50 | 0:70c8e56bac45 | 461 | if (p->code[i+4] == ir->FF) { |
yuhki50 | 0:70c8e56bac45 | 462 | ir->code[i+3] = 0xFF; |
yuhki50 | 0:70c8e56bac45 | 463 | } else if (p->code[i+4] > 0xFE) { |
yuhki50 | 0:70c8e56bac45 | 464 | DEBUGF("\n%04X : Mark/Space overflow\n", p->code[i+4]); |
yuhki50 | 0:70c8e56bac45 | 465 | return false; |
yuhki50 | 0:70c8e56bac45 | 466 | } else { |
yuhki50 | 0:70c8e56bac45 | 467 | ir->code[i+3] = (p->code[i+4] * p->usec) / USECPERTICK; |
yuhki50 | 0:70c8e56bac45 | 468 | } |
yuhki50 | 0:70c8e56bac45 | 469 | DEBUGF("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]); |
yuhki50 | 0:70c8e56bac45 | 470 | } |
yuhki50 | 0:70c8e56bac45 | 471 | DEBUGF("|\n"); |
yuhki50 | 0:70c8e56bac45 | 472 | |
yuhki50 | 0:70c8e56bac45 | 473 | ir->FF = (ir->FF * p->usec) / USECPERTICK; |
yuhki50 | 0:70c8e56bac45 | 474 | DEBUGF("FF -> %d\n", ir->FF); |
yuhki50 | 0:70c8e56bac45 | 475 | |
yuhki50 | 0:70c8e56bac45 | 476 | return true; |
yuhki50 | 0:70c8e56bac45 | 477 | } |
yuhki50 | 0:70c8e56bac45 | 478 | |
yuhki50 | 0:70c8e56bac45 | 479 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 480 | // |
yuhki50 | 0:70c8e56bac45 | 481 | void irDump (irCode_t* ir) |
yuhki50 | 0:70c8e56bac45 | 482 | { |
yuhki50 | 0:70c8e56bac45 | 483 | int i, len; |
yuhki50 | 0:70c8e56bac45 | 484 | |
yuhki50 | 0:70c8e56bac45 | 485 | printf("uint8_t buttonName[%d] = {", len); |
yuhki50 | 0:70c8e56bac45 | 486 | |
yuhki50 | 0:70c8e56bac45 | 487 | printf("%d,%d, ", (ir->FF >> 8), ir->FF & 0xFF); |
yuhki50 | 0:70c8e56bac45 | 488 | printf("%d,%d,%d, ", ir->code[0], ir->code[1], ir->code[2]); |
yuhki50 | 0:70c8e56bac45 | 489 | |
yuhki50 | 0:70c8e56bac45 | 490 | len = (ir->code[1] * 2) + (ir->code[2] * 2); |
yuhki50 | 0:70c8e56bac45 | 491 | for (i = 0; i < len; i++) { |
yuhki50 | 0:70c8e56bac45 | 492 | printf("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]); |
yuhki50 | 0:70c8e56bac45 | 493 | } |
yuhki50 | 0:70c8e56bac45 | 494 | |
yuhki50 | 0:70c8e56bac45 | 495 | printf("};\n"); |
yuhki50 | 0:70c8e56bac45 | 496 | |
yuhki50 | 0:70c8e56bac45 | 497 | } |
yuhki50 | 0:70c8e56bac45 | 498 | |
yuhki50 | 0:70c8e56bac45 | 499 | //+============================================================================= |
yuhki50 | 0:70c8e56bac45 | 500 | // |
yuhki50 | 0:70c8e56bac45 | 501 | int main ( ) |
yuhki50 | 0:70c8e56bac45 | 502 | { |
yuhki50 | 0:70c8e56bac45 | 503 | pronto_t pCode; |
yuhki50 | 0:70c8e56bac45 | 504 | irCode_t irCode; |
yuhki50 | 0:70c8e56bac45 | 505 | |
yuhki50 | 0:70c8e56bac45 | 506 | decode(prontoTest, &pCode, &irCode); |
yuhki50 | 0:70c8e56bac45 | 507 | |
yuhki50 | 0:70c8e56bac45 | 508 | irDump(&irCode); |
yuhki50 | 0:70c8e56bac45 | 509 | |
yuhki50 | 0:70c8e56bac45 | 510 | return 0; |
yuhki50 | 0:70c8e56bac45 | 511 | } |
yuhki50 | 0:70c8e56bac45 | 512 | |
yuhki50 | 0:70c8e56bac45 | 513 | #endif //0 |