├── Frankenverter 1.0.0 D-15 pinout.pdf ├── a429.h ├── a429_device.h ├── arduino_io.h ├── delay.h ├── FrankenVerter.ino └── avrio.h /Frankenverter 1.0.0 D-15 pinout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncormia/FrankenVerter/HEAD/Frankenverter 1.0.0 D-15 pinout.pdf -------------------------------------------------------------------------------- /a429.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | /************************************ 3 | a429.h 4 | *************************************/ 5 | #ifndef A429_H 6 | #define A429_H 7 | 8 | /* Here I define a buffer space to hold the ARINC 429 words */ 9 | #define MAXARINCWORDS 500 10 | /* 11 | struct arinc429array 12 | { 13 | unsigned int count; 14 | struct arinc429_data 15 | { 16 | unsigned long int time; 17 | unsigned long int data; 18 | unsigned short bus; 19 | } a429; 20 | } rx[MAXARINCWORDS]; 21 | */ 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /a429_device.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////////////////////// 2 | // #include "a429_device.h" 3 | /************************************ 4 | a429_device.h 5 | *************************************/ 6 | #ifndef A429_DEVICE_H 7 | #define A429_DEVICE_H 8 | 9 | 10 | /* Inputs from the ARINC UART */ 11 | int a429DR1_pin = 2; 12 | int a429DR2_pin = 3; 13 | int a429TXR_pin = 9; 14 | 15 | /* Outputs to the ARINC UART */ 16 | int a429SEL_pin = 4; 17 | int a429OE1_pin = 5; 18 | int a429OE2_pin = 6; 19 | int a429LD1_pin = 7; 20 | int a429LD2_pin = 8; 21 | int a429ENTX_pin = 10; 22 | int a429LDCW_pin = 11; 23 | int a429MR_pin = 12; 24 | int a429DBCEN_pin = 13; 25 | 26 | // 16 additional pins are used for the data bus. 27 | // I'm using PORTA and PORTC, mega pins 22-37 28 | 29 | // Now define several timer values for communicating with the DEI 1016: 30 | // These are in nano seconds. 31 | int Tmr = 200; //master reset 32 | int Tpwld = 130; 33 | int Tsdw = 110; 34 | int Tddr = 200; 35 | int Tssel = 20; 36 | int Thsel = 20; 37 | int Tpwoe = 200; 38 | int Toeoe = 30; 39 | int Tdoedr = 200; 40 | 41 | 42 | /* 43 | These defines are the bit values that enable/disable settings of the 44 | ARINC 429 UART. 45 | */ 46 | #define PAREN 0x10; // PARity ENable 47 | #define SLFTST 0x00; // SeLF TeST 48 | #define NOTSLFTST 0x20; // Not SeLF TeST 49 | #define PARCK 0x10; // PARity ChecK 50 | #define TXLO 0x20; // TX (transmit) LOw speed 51 | #define TXHI 0x00; // TX (transmit) HIgh speed 52 | #define RXLO 0x40; // RX (receive) LOw speed 53 | #define RXHI 0x00; // RX (receive) HIgh speed 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /arduino_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arduino_io.h 3 | * this file maps arduino pins to avr ports and pins 4 | * 5 | * The header file: pins_arduino.h is used if this exits 6 | * otherwise the following controllers are defined in this file 7 | * Arduino (ATmega8,168,328), Mega, Sanguino (ATmega644P) 8 | * 9 | * Thanks to Paul Stoffregen (http://www.pjrc.com/teensy) 10 | * for his expertise in Arduino pin mapping macros 11 | */ 12 | 13 | #include "pins_arduino.h" 14 | #if !(defined(digitalPinToPortReg) && defined(digitalPinToBit)) 15 | #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) 16 | 17 | // Standard Arduino Pins 18 | #define digitalPinToPortReg(P) \ 19 | (((P) >= 0 && (P) <= 7) ? &PORTD : (((P) >= 8 && (P) <= 13) ? &PORTB : &PORTC)) 20 | #define digitalPinToBit(P) \ 21 | (((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14)) 22 | 23 | #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 24 | // Arduino Mega Pins 25 | #define digitalPinToPortReg(P) \ 26 | (((P) >= 22 && (P) <= 29) ? &PORTA : \ 27 | ((((P) >= 10 && (P) <= 13) || ((P) >= 50 && (P) <= 53)) ? &PORTB : \ 28 | (((P) >= 30 && (P) <= 37) ? &PORTC : \ 29 | ((((P) >= 18 && (P) <= 21) || (P) == 38) ? &PORTD : \ 30 | ((((P) >= 0 && (P) <= 3) || (P) == 5) ? &PORTE : \ 31 | (((P) >= 54 && (P) <= 61) ? &PORTF : \ 32 | ((((P) >= 39 && (P) <= 41) || (P) == 4) ? &PORTG : \ 33 | ((((P) >= 6 && (P) <= 9) || (P) == 16 || (P) == 17) ? &PORTH : \ 34 | (((P) == 14 || (P) == 15) ? &PORTJ : \ 35 | (((P) >= 62 && (P) <= 69) ? &PORTK : &PORTL)))))))))) 36 | #define digitalPinToBit(P) \ 37 | (((P) >= 7 && (P) <= 9) ? (P) - 3 : \ 38 | (((P) >= 10 && (P) <= 13) ? (P) - 6 : \ 39 | (((P) >= 22 && (P) <= 29) ? (P) - 22 : \ 40 | (((P) >= 30 && (P) <= 37) ? 37 - (P) : \ 41 | (((P) >= 39 && (P) <= 41) ? 41 - (P) : \ 42 | (((P) >= 42 && (P) <= 49) ? 49 - (P) : \ 43 | (((P) >= 50 && (P) <= 53) ? 53 - (P) : \ 44 | (((P) >= 54 && (P) <= 61) ? (P) - 54 : \ 45 | (((P) >= 62 && (P) <= 69) ? (P) - 62 : \ 46 | (((P) == 0 || (P) == 15 || (P) == 17 || (P) == 21) ? 0 : \ 47 | (((P) == 1 || (P) == 14 || (P) == 16 || (P) == 20) ? 1 : \ 48 | (((P) == 19) ? 2 : \ 49 | (((P) == 5 || (P) == 6 || (P) == 18) ? 3 : \ 50 | (((P) == 2) ? 4 : \ 51 | (((P) == 3 || (P) == 4) ? 5 : 7))))))))))))))) 52 | 53 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 54 | // Sanguino or other ATmega644 controller 55 | #define digitalPinToPortReg(P) \ 56 | (((P) >= 0 && (P) <= 7) ? &PORTB : \ 57 | (((P) >= 8 && (P) <= 15) ? &PORTD : \ 58 | (((P) >= 16 && (P) <= 23) ? &PORTC : &PORTA))) 59 | #define digitalPinToBit(P) \ 60 | (((P) >= 0 && (P) <= 23) ? (P%8) : (7-(P%8)) ) 61 | //#error "ATmega644 has not been tested" 62 | #else 63 | #error "Arduino pin mapping not defined for this board" 64 | #endif 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /delay.h: -------------------------------------------------------------------------------- 1 | /* 2 | * delay.h 3 | * 4 | * Provides accurate delays for a given number of nanoseconds 5 | * This version is part of the Arduino GLCD library. 6 | * 7 | * This file is based on code by Copyright Hans-Juergen Heinrichs (c) 2005 8 | * 9 | * the following comment is from his file 10 | * The idea for the functions below was heavily inspired by the 11 | * file which is part of the excellent WinAVR 12 | * distribution. Therefore, thanks to Marek Michalkiewicz and 13 | * Joerg Wunsch. 14 | * 15 | * The idea is to have the GCC preprocessor handle all calculations 16 | * necessary for determining the exact implementation of a delay 17 | * algorithm. The implementation itself is then inlined into the 18 | * user code. 19 | * In this way it is possible to always get the code size optimized 20 | * delay implementation. 21 | * 22 | */ 23 | 24 | /* 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 29 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef _ARDUINO_DELAY_H_ 40 | #define _ARDUINO_DELAY_H_ 41 | 42 | #include 43 | 44 | #ifndef F_CPU 45 | # warning "Macro F_CPU must be defined" 46 | #endif 47 | 48 | /* 49 | * Forward declaration for all functions with attribute 50 | * 'always_inline' enforces GCC to inline the code (even 51 | * if it would be better not to do so from optimization 52 | * perspective). 53 | * Without this attribute GCC is free to implement 54 | * inline code or not (using the keyword 'inline' 55 | * alone is not sufficient). 56 | * 57 | */ 58 | static __inline__ void _NOP1( void) __attribute__((always_inline)); 59 | static __inline__ void _NOP2( void) __attribute__((always_inline)); 60 | static __inline__ void _NOP3( void) __attribute__((always_inline)); 61 | static __inline__ void _NOP4( void) __attribute__((always_inline)); 62 | static __inline__ void _NOP5( void) __attribute__((always_inline)); 63 | static __inline__ void _NOP6( void) __attribute__((always_inline)); 64 | static __inline__ void _NOP7( void) __attribute__((always_inline)); 65 | static __inline__ void _NOP8( void) __attribute__((always_inline)); 66 | static __inline__ void _NOP9( void) __attribute__((always_inline)); 67 | static __inline__ void _NOP10(void) __attribute__((always_inline)); 68 | static __inline__ void _NOP11(void) __attribute__((always_inline)); 69 | static __inline__ void _NOP12(void) __attribute__((always_inline)); 70 | 71 | static __inline__ void _delay_loop_3( uint32_t) __attribute__((always_inline)); 72 | static __inline__ void _delay_loop_1_x( uint8_t) __attribute__((always_inline)); 73 | static __inline__ void _delay_loop_2_x(uint16_t) __attribute__((always_inline)); 74 | static __inline__ void _delay_loop_3_x(uint32_t) __attribute__((always_inline)); 75 | 76 | static __inline__ void _delay_cycles(const double) __attribute__((always_inline)); 77 | 78 | 79 | /* 80 | * _ N O P x ( void ) 81 | * 82 | * Code sized optimized NOPs - not using any registers 83 | * 84 | * These NOPs will be used for very short delays where 85 | * it is more code efficient than executing loops. 86 | * 87 | */ 88 | static __inline__ void _NOP1 (void) { __asm__ volatile ( "nop " "\n\t" ); } 89 | static __inline__ void _NOP2 (void) { __asm__ volatile ( "rjmp 1f" "\n\t" "1:" "\n\t" ); } 90 | static __inline__ void _NOP3 (void) { __asm__ volatile ( "lpm " "\n\t" ); } 91 | static __inline__ void _NOP4 (void) { _NOP3(); _NOP1(); } 92 | static __inline__ void _NOP5 (void) { _NOP3(); _NOP2(); } 93 | static __inline__ void _NOP6 (void) { _NOP3(); _NOP3(); } 94 | static __inline__ void _NOP7 (void) { _NOP3(); _NOP3(); _NOP1(); } 95 | static __inline__ void _NOP8 (void) { _NOP3(); _NOP3(); _NOP2(); } 96 | static __inline__ void _NOP9 (void) { _NOP3(); _NOP3(); _NOP3(); } 97 | static __inline__ void _NOP10(void) { _NOP3(); _NOP3(); _NOP3(); _NOP1(); } 98 | static __inline__ void _NOP11(void) { _NOP3(); _NOP3(); _NOP3(); _NOP2(); } 99 | static __inline__ void _NOP12(void) { _NOP3(); _NOP3(); _NOP3(); _NOP3(); } 100 | 101 | 102 | 103 | /* 104 | * _ d e l a y _ l o o p _ 3( uint32_t __count ) 105 | * 106 | * This delay loop is not used in the code below: It is 107 | * a supplement to the _delay_loop_1() and _delay_loop_2() 108 | * within standard WinAVR giving a wider 109 | * (32 bit) delay range. 110 | * 111 | */ 112 | static __inline__ void 113 | _delay_loop_3( uint32_t __count ) 114 | { 115 | __asm__ volatile ( 116 | "1: sbiw %A0,1" "\n\t" 117 | "sbc %C0,__zero_reg__" "\n\t" 118 | "sbc %D0,__zero_reg__" "\n\t" 119 | "brne 1b" 120 | : "=w" (__count) 121 | : "0" (__count) 122 | ); 123 | } 124 | 125 | 126 | /* 127 | * _ d e l a y _ l o o p _ 1 _ x( uint8_t __count ) 128 | * _ d e l a y _ l o o p _ 2 _ x( uint16_t __count ) 129 | * _ d e l a y _ l o o p _ 4 _ x( uint32_t __count ) 130 | * 131 | * These delay loops always have exactly 4(8) cycles per loop. 132 | * They use a 8/16/32 bit register counter respectively. 133 | * 134 | */ 135 | static __inline__ void /* exactly 4 cycles/loop, max 2**8 loops */ 136 | _delay_loop_1_x( uint8_t __n ) 137 | { /* cycles per loop */ 138 | __asm__ volatile ( /* __n..one zero */ 139 | "1: dec %0" "\n\t" /* 1 1 */ 140 | " breq 2f" "\n\t" /* 1 2 */ 141 | "2: brne 1b" "\n\t" /* 2 1 */ 142 | : "=r" (__n) /* ----- ----- */ 143 | : "0" (__n) /* 4 4 */ 144 | ); 145 | } 146 | 147 | static __inline__ void /* exactly 4 cycles/loop, max 2**16 loops */ 148 | _delay_loop_2_x( uint16_t __n ) 149 | { /* cycles per loop */ 150 | __asm__ volatile ( /* __n..one zero */ 151 | "1: sbiw %0,1" "\n\t" /* 2 2 */ 152 | " brne 1b " "\n\t" /* 2 1 */ 153 | " nop " "\n\t" /* 1 */ 154 | : "=w" (__n) /* ----- ----- */ 155 | : "0" (__n) /* 4 4 */ 156 | ); 157 | } 158 | 159 | static __inline__ void /* exactly 8 cycles/loop, max 2**32 loops */ 160 | _delay_loop_3_x( uint32_t __n ) 161 | { /* cycles per loop */ 162 | __asm__ volatile ( /* __n..one zero */ 163 | "1: sbiw %A0,1 " "\n\t" /* 2 2 */ 164 | " sbc %C0,__zero_reg__" "\n\t" /* 1 1 */ 165 | " sbc %D0,__zero_reg__" "\n\t" /* 1 1 */ 166 | " nop " "\n\t" /* 1 1 */ 167 | " breq 2f " "\n\t" /* 1 2 */ 168 | "2: brne 1b " "\n\t" /* 2 1 */ 169 | : "=w" (__n) /* ----- ----- */ 170 | : "0" (__n) /* 8 8 */ 171 | ); 172 | } 173 | 174 | 175 | /* 176 | * 177 | * _ d e l a y _ c y c l e s (double __ticks_d) 178 | * 179 | * Perform an accurate delay of a given number of processor cycles. 180 | * 181 | * All the floating point arithmetic will be handled by the 182 | * GCC Preprocessor and no floating point code will be generated. 183 | * Allthough the parameter __ticks_d is of type 'double' this 184 | * function can be called with any constant integer value, too. 185 | * GCC will handle the casting appropriately. 186 | * 187 | * With an 8 MHz clock e.g., delays ranging from 125 nanoseconds 188 | * up to (2**32-1) * 125ns ~= 536,87 seconds are feasible. 189 | * 190 | */ 191 | static __inline__ void 192 | _delay_cycles(const double __ticks_d) 193 | { 194 | uint32_t __ticks = (uint32_t)(__ticks_d); 195 | uint32_t __padding; 196 | uint32_t __loops; 197 | 198 | /* 199 | * Special optimization for very 200 | * small delays - not using any register. 201 | */ 202 | if( __ticks <= 12 ) { /* this can be done with 4 opcodes */ 203 | __padding = __ticks; 204 | 205 | /* create a single byte counter */ 206 | } else if( __ticks <= 0x400 ) { 207 | __ticks -= 1; /* caller needs 1 cycle to init counter */ 208 | __loops = __ticks / 4; 209 | __padding = __ticks % 4; 210 | if( __loops != 0 ) 211 | _delay_loop_1_x( (uint8_t)__loops ); 212 | 213 | /* create a two byte counter */ 214 | } else if( __ticks <= 0x40001 ) { 215 | __ticks -= 2; /* caller needs 2 cycles to init counter */ 216 | __loops = __ticks / 4; 217 | __padding = __ticks % 4; 218 | if( __loops != 0 ) 219 | _delay_loop_2_x( (uint16_t)__loops ); 220 | 221 | /* create a four byte counter */ 222 | } else { 223 | __ticks -= 4; /* caller needs 4 cycles to init counter */ 224 | __loops = __ticks / 8; 225 | __padding = __ticks % 8; 226 | if( __loops != 0 ) 227 | _delay_loop_3_x( (uint32_t)__loops ); 228 | } 229 | 230 | if( __padding == 1 ) _NOP1(); 231 | if( __padding == 2 ) _NOP2(); 232 | if( __padding == 3 ) _NOP3(); 233 | if( __padding == 4 ) _NOP4(); 234 | if( __padding == 5 ) _NOP5(); 235 | if( __padding == 6 ) _NOP6(); 236 | if( __padding == 7 ) _NOP7(); 237 | if( __padding == 8 ) _NOP8(); 238 | if( __padding == 9 ) _NOP9(); 239 | if( __padding == 10 ) _NOP10(); 240 | if( __padding == 11 ) _NOP11(); 241 | if( __padding == 12 ) _NOP12(); 242 | } 243 | 244 | 245 | /* 246 | * _ d e l a y _ n s (double __ns) 247 | * _ d e l a y _ u s (double __us) 248 | * 249 | * Perform a very exact delay with a resolution as accurate as a 250 | * single CPU clock (the macro F_CPU is supposed to be defined to a 251 | * constant defining the CPU clock frequency in Hertz). 252 | * 253 | */ 254 | #define _delayNanoseconds(__ns) _delay_cycles( (double)(F_CPU)*((double)__ns)/1.0e9 + 0.5 ) 255 | 256 | #endif /* _ARDUINO_DELAY_H_ */ 257 | 258 | -------------------------------------------------------------------------------- /FrankenVerter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | FRANKENVERTER 1.0 10/1/2011 3 | 4 | An ARINC 429 to NMEA 0183 and SL30 (Garmin Nav Radio) converter. The Frankenverter 5 | is built as an Arduino Mega Sheild and takes ARINC 429 line level inputs and transcodes 6 | the GPS specific input into NMEA 0183 (for enroute and terminal) and SL30 format 7 | sentences (for approach/LPV). 8 | 9 | Also, input from Dynon EFIS telemetry is converted to Shadin FADC (air-data) format 10 | for use by Garmin 4/500 series Navigation GPS units. 11 | 12 | The PCB is available at: http://batchpcb.com/index.php/Products/75449 13 | This Arduino shield is compatible with Arduino Mega 2560 (R2) and probably 1280 as well 14 | 15 | TO DO: 16 | - Need to publish a BOM for the PCB! For now: 17 | DEI1016B ARINC line-driver chip 18 | 77956 CONN,DSUB,.318"RT,15P-F (jameco.com) 19 | 71618 SOCKET,PLCC,44 PIN,SOLDERTAIL (jameco.com) 20 | 1 MHZ 7mmx5mm SMD 5V Crystal Oscillator (http://www.ebay.com/itm/10-PCS-1MHz-5-7-SMT-1-MHz-1-000MHz-Crystal-Oscillator-/120874623633) 21 | MAX233ACWP RS232 Line Driver (digikey.com) 22 | (sorry about the smd parts…) 23 | 24 | - Major cleanup of vars and defines 25 | - Better comments for key code features: explain why the insane Serial output settings... 26 | - Factor code to reduce footprint 27 | - Re-establish some sanity of the Serial telemetry output controlled by DEBUG_SERIAL 28 | 29 | Written by Neil Cormia 30 | Based on work of Mark Ewert (http://www.instructables.com/id/Interfacing-Electronic-Circuits-to-Arduinos/) 31 | 32 | */ 33 | 34 | #include 35 | #include "arduino_io.h" // these macros map arduino pins 36 | #include "a429.h" 37 | #include "a429_device.h" 38 | #include "delay.h" 39 | #include "avrio.h" // these macros do direct port io 40 | 41 | ////////////////////////////////////////////////////////////////////////////////////////////////// 42 | // Now define several utility functions for accurate AVR timing delay 43 | #define DelayNanoseconds(__SN) _delay_cycles( (double)(F_CPU)*((double)__SN)/1.0e9 + 0.5 ) // Hans Heinrichs delay cycle routine 44 | #define fastWrite(pin, pinval) avrio_WritePin(pin, pinval) 45 | 46 | #define NMEA_DELAY_MS 100 // 10 updates per second 47 | 48 | int inByte = 0; // incoming Serial byte 49 | int Test_Output = 0; 50 | int Test_Rate = 100; 51 | int Test_VNAV = 0; 52 | 53 | byte controlword1; 54 | byte controlword2; 55 | 56 | long r1_activity_off_time = 0; 57 | long r2_activity_off_time = 0; 58 | 59 | boolean r1_activity = false; 60 | boolean r2_activity = false; 61 | 62 | /************************************************************************************************* 63 | busoutput 64 | This module sets the bus pins to outputs 65 | **************************************************************************************************/ 66 | void busoutput() 67 | { 68 | int i; 69 | //for (i=22;i<=37;i++) 70 | // pinMode(i,OUTPUT); 71 | DDRA = 0xFF; 72 | DDRC = 0xFF; 73 | } 74 | 75 | /************************************************************************************************* 76 | busHiZ 77 | This module sets the bus pins to inputs. 78 | **************************************************************************************************/ 79 | void busHiZ() 80 | { 81 | int i; 82 | PORTA = 0x00; 83 | PORTC = 0x00; 84 | DDRA = 0x00; 85 | DDRC = 0x00; 86 | // for (i=22;i<=37;i++) 87 | // pinMode(i,INPUT); 88 | } 89 | 90 | /************************************************************************************************* 91 | DEBUG to control Serial Output 92 | **************************************************************************************************/ 93 | #ifdef DEBUG_SERIAL 94 | #define SerialPrint(A) Serial.print A 95 | #define SerialPrintln(A) Serial.println A 96 | #else 97 | #define SerialPrint(A) (void)0 98 | #define SerialPrintln(A) (void)0 99 | #endif 100 | 101 | /************************************************************************************************* 102 | setup 103 | Standard setup module for arduinos 104 | **************************************************************************************************/ 105 | void setup() 106 | { 107 | // start Serial port: 108 | Serial.begin(115200); // DEBUG output and control input (USB) 109 | 110 | Serial1.begin(9600); // Input from GPSMAP (optional) | Shadin FADC Output to GPS 400W 111 | Serial2.begin(115200); // Logging Input from Dynon EFIS 112 | Serial3.begin(9600); // NMEA Output to Dynon 100/180 113 | 114 | pinMode(a429DR1_pin, INPUT); 115 | pinMode(a429DR2_pin, INPUT); 116 | pinMode(a429TXR_pin, INPUT); 117 | pinMode(a429SEL_pin, OUTPUT); 118 | pinMode(a429OE1_pin, OUTPUT); 119 | pinMode(a429OE2_pin, OUTPUT); 120 | pinMode(a429LD1_pin, OUTPUT); 121 | pinMode(a429LD2_pin, OUTPUT); 122 | pinMode(a429ENTX_pin, OUTPUT); 123 | pinMode(a429LDCW_pin, OUTPUT); 124 | pinMode(a429DBCEN_pin, OUTPUT); 125 | pinMode(a429MR_pin, OUTPUT); 126 | 127 | // Init Annunciators 128 | #define Annunciate_TRM 20 129 | #define Annunciate_APR 21 130 | pinMode(Annunciate_TRM, OUTPUT); 131 | pinMode(Annunciate_APR, OUTPUT); 132 | 133 | 134 | /* initialize the ARINC uart */ 135 | digitalWrite(a429MR_pin,HIGH); 136 | digitalWrite(a429SEL_pin,HIGH); 137 | digitalWrite(a429OE1_pin,HIGH); 138 | digitalWrite(a429OE2_pin,HIGH); 139 | digitalWrite(a429LD1_pin,HIGH); 140 | digitalWrite(a429LD2_pin,HIGH); 141 | digitalWrite(a429ENTX_pin,HIGH); 142 | digitalWrite(a429LDCW_pin,HIGH); 143 | digitalWrite(a429DBCEN_pin,HIGH); 144 | 145 | controlword1 = NOTSLFTST; 146 | controlword1 |= PAREN; // enable normal operations and parity generator 147 | controlword2 = TXLO; 148 | controlword2 |= RXLO; // high speed TX, low speed RX 149 | SerialPrint(("setup: ")); 150 | SerialPrintln((controlword2, HEX)); 151 | 152 | 153 | busoutput(); 154 | } 155 | 156 | /************************************************************************************************* 157 | resetARINC 158 | This module resets the ARINC 429 transceiver and set it up per controlword1 and 2 settings. 159 | **************************************************************************************************/ 160 | void resetARINC() 161 | { 162 | byte temp; 163 | // lower then raise MR 164 | delayMicroseconds(100); 165 | fastWrite(a429MR_pin,LOW); 166 | delayMicroseconds(10); 167 | fastWrite(a429MR_pin,HIGH); 168 | 169 | // Now load control word 170 | fastWrite(a429LDCW_pin,LOW); 171 | PORTA = controlword1; 172 | PORTC = controlword2; 173 | delayMicroseconds(1); // let them settle a bit 174 | fastWrite(a429LDCW_pin,HIGH); 175 | delayMicroseconds(100); 176 | 177 | SerialPrint(("resetARINC: ")); 178 | SerialPrintln((controlword2, HEX)); 179 | 180 | } 181 | 182 | /************************************************************************************************* 183 | txARINC 184 | This module transmits a test ARINC word for testing 185 | **************************************************************************************************/ 186 | void txARINC() 187 | { 188 | fastWrite(a429ENTX_pin,LOW); 189 | delayMicroseconds(1); 190 | fastWrite(a429LD1_pin,LOW); 191 | PORTA = 0x12; 192 | PORTC = 0x34; 193 | delayMicroseconds(1); 194 | fastWrite(a429LD1_pin,HIGH); 195 | delayMicroseconds(1); // let them settle a bit 196 | fastWrite(a429LD2_pin,LOW); 197 | PORTA = 0x56; 198 | PORTC = 0x78; 199 | delayMicroseconds(1); 200 | fastWrite(a429LD2_pin,HIGH); 201 | delayMicroseconds(1); 202 | fastWrite(a429ENTX_pin,HIGH); 203 | } 204 | 205 | 206 | 207 | /************************************************************************************************* 208 | rxARINC 209 | This module receives the ARINC words from either reciever which has data waiting. 210 | **************************************************************************************************/ 211 | void rxARINC() 212 | { 213 | int rx1, rx2; 214 | unsigned short int b1,b2,b3,b4; 215 | 216 | 217 | // Read from the ARINC 1 input [DSUB-15 connector: pin 11 (ARINC-A) and pin 4 (ARINC-B)] 218 | // 219 | rx1 = digitalRead(a429DR1_pin); 220 | if (rx1 ==0) // rx1 has data 221 | { 222 | r1_activity_off_time = millis() + 50; // add 50 millis 223 | r1_activity = true; 224 | //fastWrite(rx1activity,LOW); 225 | busHiZ(); 226 | fastWrite(a429SEL_pin,LOW); 227 | DelayNanoseconds(Tssel); 228 | fastWrite(a429OE1_pin,LOW); 229 | DelayNanoseconds(Tpwoe); 230 | b1 = PINA; 231 | b2 = PINC; 232 | fastWrite(a429OE1_pin,HIGH); 233 | DelayNanoseconds(Thsel); 234 | fastWrite(a429SEL_pin,HIGH); 235 | DelayNanoseconds(Toeoe); 236 | fastWrite(a429OE1_pin,LOW); 237 | DelayNanoseconds(Tdoedr); 238 | b3 = PINA; 239 | b4 = PINC; 240 | fastWrite(a429OE1_pin,HIGH); 241 | busoutput(); 242 | 243 | parse_ARINC(b1,b2,b3,b4); 244 | } 245 | 246 | /* 247 | // Read from the ARINC 2 input [DSUB-15 connector: pin 10 (ARINC-A) and pin 3 (ARINC-B)] 248 | // 249 | rx2 = digitalRead(a429DR2_pin); 250 | if (rx2==0) // rx2 has data 251 | { 252 | r2_activity_off_time = millis() + 50; // add 50 millis 253 | r2_activity = true; 254 | fastWrite(rx2activity,LOW); 255 | busHiZ(); 256 | fastWrite(a429SEL_pin,LOW); 257 | DelayNanoseconds(Tssel); 258 | fastWrite(a429OE2_pin,LOW); 259 | DelayNanoseconds(Tpwoe); 260 | b1 = PINA; 261 | b2 = PINC; 262 | fastWrite(a429OE2_pin,HIGH); 263 | DelayNanoseconds(Thsel); 264 | fastWrite(a429SEL_pin,HIGH); 265 | DelayNanoseconds(Toeoe); 266 | fastWrite(a429OE2_pin,LOW); 267 | DelayNanoseconds(Tdoedr); 268 | b3 = PINA; 269 | b4 = PINC; 270 | fastWrite(a429OE2_pin,HIGH); 271 | busoutput(); 272 | SerialPrint(("r"); 273 | SerialPrint((b4, HEX); 274 | SerialPrint((b3, HEX); 275 | SerialPrint((b2, HEX); 276 | SerialPrintln((b1, HEX); 277 | } 278 | */ 279 | 280 | } 281 | 282 | 283 | 284 | // ------------------------------------------------------------------------------------------- 285 | // RECORD THE ARINC LABELS ARRIVING TO ELIMINATE DUPLICATE REPORTING 286 | word label_table[300]; 287 | byte b2_table[300]; 288 | 289 | // Flight Plan Info Struct 290 | struct FPStruct { 291 | int stationtype; 292 | float wptlatitude; 293 | int wptlatSN; 294 | float wptlongitude; 295 | int wptlongWE; 296 | char msgbuf[8]; 297 | } FlitePlan[21]; 298 | 299 | // Store persistant data values received in the ARINC stream 300 | int MagVar_WE; 301 | float MagVar = 0; 302 | char MsgBuf[16]; 303 | char GMTBuf[8]; 304 | char DateBuf[8]; 305 | int StationType = 0; 306 | int OnRoute = 0; 307 | int WaypointNumber = 0; 308 | int NumWaypoints = 0; 309 | int FromWPT = 0; 310 | int ToWPT = 0; 311 | 312 | float VerticalDeviation = 0; 313 | int VerticalDev_UD; 314 | float CrossTrackDist; 315 | int CrossTrack_RL; 316 | 317 | float SelectedCourse; 318 | float ETDest; 319 | float DistanceToDest; 320 | float DistanceToGo; 321 | float TrackAngle; 322 | float GroundSpeed; 323 | float WPT_Bearing; 324 | float DesiredTrack; 325 | 326 | float WPT_Latitude; 327 | int WPT_Lat_SN; 328 | float WPT_Longitude; 329 | int WPT_Long_WE; 330 | float PP_Latitude; 331 | int PP_Lat_SN; 332 | float PP_Longitude; 333 | int PP_Long_WE; 334 | 335 | long NMEA_delay = 0; 336 | int SL30_Count = 0; 337 | 338 | 339 | // ------------- GlideSlope and Localizer flags and values ------------- 340 | // These are timeout values that are set to (???) MSec when valid and count down to zero if 341 | // no updates occur or if an invalid data flag is sensed. NOT USED!!!! 342 | #define GS_VALID_TIME 1000 343 | #define LOC_VALID_TIME 1000 344 | 345 | #define BC_Enable 0x01 346 | #define LOC_Detect 0x02 347 | #define FROM_Flag 0x04 348 | #define TO_Flag 0x08 349 | #define GSI_Super 0x10 350 | #define GSI_Valid 0x20 351 | #define NAV_Super 0x40 352 | #define NAV_Valid 0x80 353 | 354 | #define GPS_ENROUTE 0 355 | #define GPS_TERMINAL 20 356 | #define GPS_APPROACH 21 357 | 358 | int GPS_Range = GPS_ENROUTE; 359 | 360 | 361 | int GS_Valid = 0; 362 | int LOC_Valid = 0; 363 | 364 | float VertScaleFactor = 0; 365 | float LatScaleFactor = 0; 366 | 367 | int VerticalDeflection, HorizontalDeflection; 368 | 369 | // ------------------------------------------------------------------------------------------- 370 | // NMEA OUTPUT FUNCTIONS 371 | // 372 | // - - - - - - - - - - - - - - - - - - - - - - - - - 373 | // PMMRRV25 - Label for Decoded Station ID (Apollo SL30 IM p71) 374 | // 375 | void outputStation(void) 376 | { 377 | char buf[64]; 378 | byte i,chksum, flags = 0; 379 | int crs; 380 | 381 | buf[0] = 0; 382 | 383 | // NMEA Label 384 | strcpy(buf, "$PMRRV25V"); 385 | 386 | strcat(buf, FlitePlan[ToWPT].msgbuf); 387 | 388 | // Append spaces to pad ID to 5 characters 389 | for (i=0; i<(5-strlen(FlitePlan[ToWPT].msgbuf)); i++) 390 | strcat(buf," "); 391 | 392 | // Calculate one byte checksum 393 | appendSL30checksum(buf); 394 | 395 | // Send to RS-232 Out #2 on FrankenVerter 396 | Serial3.write((byte *)buf, strlen(buf)); 397 | //SerialPrint((buf)); 398 | } 399 | 400 | // PMMRRV22 - Label for LPV/LNAV+V OBS (Apollo SL30 IM p71) 401 | // 402 | void outputOBS(void) 403 | { 404 | char buf[64]; 405 | byte i,chksum, flags = 0; 406 | int crs; 407 | 408 | buf[0] = 0; 409 | 410 | // NMEA Label 411 | strcpy(buf, "$PMRRV22V"); // 8 Bytes 412 | 413 | // Waypoint to Bearing 414 | crs = int(round(SelectedCourse)); 415 | pad_int_to_string_noLR(&(buf[strlen(buf)]), crs, 3); 416 | 417 | // Calculate one byte checksum 418 | appendSL30checksum(buf); 419 | 420 | // Send to RS-232 Out #2 on FrankenVerter 421 | Serial3.write((byte *)buf, strlen(buf)); 422 | //SerialPrint((buf)); 423 | } 424 | 425 | // Output all the other SL30 sentences in case they're required by the Dynon D180 426 | // 427 | void outputActiveVOR(void) 428 | { 429 | char buf[64]; 430 | 431 | // Radial from Active VOR 432 | strcpy(buf, "$PMRRV2300"); 433 | appendSL30checksum(buf); 434 | Serial3.write((byte *)buf, strlen(buf)); 435 | //SerialPrint((buf)); 436 | } 437 | 438 | // Output all the other SL30 sentences in case they're required by the Dynon D180 439 | // 440 | void outputSL30Misc(void) 441 | { 442 | char buf[64]; 443 | 444 | // Radial from Standby VOR 445 | strcpy(buf, "$PMRRV2400"); 446 | appendSL30checksum(buf); 447 | Serial3.write((byte *)buf, strlen(buf)); 448 | //Serial.print(buf); 449 | 450 | // NAV Receiver Status 451 | strcpy(buf, "$PMRRV28E4?PN"); 452 | appendSL30checksum(buf); 453 | Serial3.write((byte *)buf, strlen(buf)); 454 | //Serial.print(buf); 455 | 456 | // COMM Tranceiver Status 457 | strcpy(buf, "$PMRRV35P4IPR0"); 458 | appendSL30checksum(buf); 459 | Serial3.write((byte *)buf, strlen(buf)); 460 | //Serial.print(buf); 461 | 462 | } 463 | 464 | // PMMRRV21 - Label for CDI/GSI (Apollo SL30 IM p71) 465 | // 466 | void outputHSI(void) 467 | { 468 | char buf[64]; 469 | byte i,chksum, flags = 0; 470 | float dist; 471 | 472 | buf[0] = 0; 473 | 474 | // NMEA Label for CDI/GSI (Apollo SL30 IM p71) 475 | strcpy(buf, "$PMRRV21"); // 8 Bytes 476 | 477 | // Convert lateral and vertical deflection into encoded hex 478 | if (LatScaleFactor > 0) { 479 | 480 | // Calculate how far off center (VSF is full deflection distance) 481 | dist = CrossTrackDist / LatScaleFactor * 100; 482 | if (dist > 100) dist = 100; 483 | if (CrossTrack_RL == 0) dist = dist * -1; 484 | 485 | // Encode LOC deflection into (HEX) as two byte ascii chars 486 | HorizontalDeflection = dist; 487 | 488 | buf[8] = ((HorizontalDeflection & 0xF0) >> 4) + 0x30; 489 | buf[9] = (HorizontalDeflection & 0x0F) + 0x30; 490 | flags |= NAV_Valid + NAV_Super; 491 | } 492 | else { 493 | buf[8] = buf[9] = '0'; 494 | } 495 | 496 | if (VertScaleFactor > 0) { 497 | 498 | // Calculate how far off center (VSF is full deflection distance) 499 | dist = VerticalDeviation / VertScaleFactor * 100; 500 | 501 | // Peg at +/- 100 502 | if (dist > 100) dist = 100; 503 | 504 | // Encode up.down into numbers 505 | if (VerticalDev_UD) { 506 | dist *= -1; 507 | } 508 | 509 | // Encode GS deflection into (HEX) as two byte ascii chars 510 | VerticalDeflection = dist; 511 | 512 | buf[10] = ((VerticalDeflection & 0xF0) >> 4) + 0x30; 513 | buf[11] = (VerticalDeflection & 0x0F) + 0x30; 514 | flags |= GSI_Valid + GSI_Super; 515 | } 516 | else { 517 | buf[10] = buf[11] = '0'; 518 | } 519 | 520 | // Encode the flags 521 | buf[12] = ((flags & 0xF0) >> 4) + 0x30; 522 | buf[13] = (flags & 0x0F) + 0x30; 523 | buf[14] = 0; 524 | 525 | // Calculate one byte checksum 526 | appendSL30checksum(buf); 527 | 528 | // Send to RS-232 Out #2 on FrankenVerter 529 | Serial3.write((byte *)buf, strlen(buf)); 530 | //Serial.print(buf); 531 | } 532 | 533 | /* 534 | ['$GPRMB', 'A', '2.14', 'L', '', 'PEBGE', '3809.0221', 'N', '12226.4855', 'W', '3.147', '23.0', '107.7', 'V', 'D*25\r\n'] 535 | 536 | RMB Recommended minimum navigation information 537 | A Data status A = OK, V = Void (warning) 538 | 0.66,L Cross-track error (nautical miles, 9.99 max), 539 | steer Left to correct (or R = right) 540 | 003 Origin waypoint ID 541 | 004 Destination waypoint ID 542 | 4917.24,N Destination waypoint latitude 49 deg. 17.24 min. N 543 | 12309.57,W Destination waypoint longitude 123 deg. 09.57 min. W 544 | 001.3 Range to destination, nautical miles (999.9 max) 545 | 052.5 True bearing to destination 546 | 000.5 Velocity towards destination, knots 547 | V Arrival alarm A = arrived, V = not arrived 548 | *20 checksum 549 | */ 550 | // - - - - - - - - - - - - - - - - - - - - - - - - - 551 | // GPRMB - Recommended Minimum Sentence B 552 | // 553 | void outputRMB(void) 554 | { 555 | char buf[128], chkbuf[8]; 556 | byte i,chksum, flags = 0; 557 | struct FPStruct* fp; 558 | float dist; 559 | 560 | buf[0] = 0; 561 | 562 | // NMEA Label for RMB 563 | strcpy(buf, "$GPRMB,"); 564 | 565 | // Valid flag 566 | strcat(buf, "A,"); 567 | 568 | // XTE - Calculate how far off center (LSF is full deflection distance) 569 | // normalize to no more than full deflection. Dynon max scale is 5 NM. 570 | // 571 | dist = CrossTrackDist / LatScaleFactor * 5; 572 | if (dist > 5) dist = 5; 573 | 574 | appendFloat(buf, dist, 2); 575 | strcat(buf, CrossTrack_RL ? ",R,":",L,"); 576 | 577 | // Origin and Dest Waypoint IDs 578 | fp = &(FlitePlan[ToWPT]); 579 | strcat(buf, FlitePlan[FromWPT].msgbuf); 580 | strcat(buf, ","); 581 | strcat(buf, fp->msgbuf); 582 | strcat(buf, ","); 583 | 584 | // Dest Lat/Long 585 | appendFloatDegrees(buf, fp->wptlatitude); 586 | strcat(buf, fp->wptlatSN ? ",S,":",N,"); 587 | appendFloatDegrees(buf, fp->wptlongitude); 588 | strcat(buf, fp->wptlongWE ? ",W,":",E,"); 589 | 590 | 591 | appendFloat(buf, DistanceToGo, 1); 592 | strcat(buf, ","); 593 | 594 | appendFloat(buf, WPT_Bearing, 1); 595 | strcat(buf, ","); 596 | 597 | appendFloat(buf, GroundSpeed, 1); 598 | strcat(buf, ","); 599 | 600 | // If more than 300 ft away we haven't arrived 601 | if (DistanceToDest < 0.05) 602 | strcat(buf, "A,"); 603 | else 604 | strcat(buf, "V,"); 605 | 606 | // D for differential, A for autonomous 607 | strcat(buf, "D"); 608 | 609 | // Calculate and attach a HEX checksum and line termination 610 | appendNMEAchecksum(buf); 611 | 612 | // Send to RS-232 Out #2 on FrankenVerter 613 | Serial3.write((byte *)buf, strlen(buf)); 614 | //Serial.println(buf); 615 | } 616 | 617 | 618 | 619 | /* 620 | ['$GPRMC', '194223', 'A', '3806.1250', 'N', '12228.0474', 'W', '107.6', '19.5', '290112', '14.2', 'E', 'D*07\r\n'] 621 | 622 | RMC Recommended Minimum sentence C 623 | 123519 Fix taken at 12:35:19 UTC 624 | A Status A=active or V=Void. 625 | 4807.038,N Latitude 48 deg 07.038' N 626 | 01131.000,E Longitude 11 deg 31.000' E 627 | 022.4 Speed over the ground in knots 628 | 084.4 Track angle in degrees True 629 | 230394 Date - 23rd of March 1994 630 | 003.1,W Magnetic Variation 631 | *6A The checksum data, always begins with * 632 | */ 633 | // - - - - - - - - - - - - - - - - - - - - - - - - - 634 | // GPRMC - Recommended Minimum Sentence C 635 | // 636 | void outputRMC(void) 637 | { 638 | char buf[128]; 639 | byte flags = 0; 640 | 641 | buf[0] = 0; 642 | 643 | // NMEA Label for RMC 644 | strcpy(buf, "$GPRMC,"); 645 | 646 | // GMT Time + Valid flag 647 | strcat(buf, GMTBuf); 648 | strcat(buf, ",A,"); 649 | 650 | // Lat/Long 651 | appendFloatDegrees(buf, PP_Latitude); 652 | strcat(buf, PP_Lat_SN ? ",S,":",N,"); 653 | appendFloatDegrees(buf, PP_Longitude); 654 | strcat(buf, PP_Long_WE ? ",W,":",E,"); 655 | 656 | appendFloat(buf, GroundSpeed, 1); 657 | strcat(buf, ","); 658 | appendFloat(buf, TrackAngle, 1); 659 | strcat(buf, ","); 660 | strcat(buf, DateBuf); 661 | strcat(buf, ","); 662 | 663 | appendFloat(buf, MagVar, 1); 664 | strcat(buf, MagVar_WE ? ",W,":",E,"); 665 | 666 | // D for differential, A for autonomous 667 | strcat(buf, "D"); 668 | 669 | // Calculate and attach a HEX checksum and line termination 670 | appendNMEAchecksum(buf); 671 | 672 | // Send to RS-232 Out #2 on FrankenVerter 673 | Serial3.write((byte *)buf, strlen(buf)); 674 | //Serial.println(buf); 675 | } 676 | 677 | /* 678 | $GPBOD,045.,T,023.,M,DEST,START*01 679 | 680 | where: 681 | BOD Bearing - origin to destination waypoint 682 | 045.,T bearing 045 True from "START" to "DEST" 683 | 023.,M bearing 023 Magnetic from "START" to "DEST" 684 | DEST destination waypoint ID 685 | START origin waypoint ID 686 | *01 checksum 687 | 688 | $GPGGA,000059,3116.6441,N,09319.0049,W,1,11,0.8,4074.0,M,000.0,M,,*5E 689 | $GPBOD,289.2,T,286.2,M,K25TE,HOME*1A 690 | 691 | */ 692 | // - - - - - - - - - - - - - - - - - - - - - - - - - 693 | // GPBOD - Bearing Origin to Destination 694 | // 695 | void outputBOD(void) 696 | { 697 | char buf[128]; 698 | byte flags = 0; 699 | 700 | buf[0] = 0; 701 | 702 | // NMEA Label for RMC 703 | strcpy(buf, "$GPBOD,"); 704 | 705 | // DTK (true) 706 | appendFloat(buf, DesiredTrack, 1); 707 | strcat(buf, ",T,"); 708 | 709 | // DTK (mag) 710 | appendFloat(buf, SelectedCourse, 1); 711 | strcat(buf, ",M,"); // blank for now 712 | 713 | // Origin and Dest Waypoint IDs 714 | strcat(buf, FlitePlan[ToWPT].msgbuf); 715 | strcat(buf, ","); 716 | strcat(buf, FlitePlan[FromWPT].msgbuf); 717 | 718 | // Calculate and attach a HEX checksum and line termination 719 | appendNMEAchecksum(buf); 720 | 721 | Serial3.write((byte *)buf, strlen(buf)); 722 | //Serial.println(buf); 723 | } 724 | 725 | 726 | /* 727 | ['$PGRMH', 'A', '185', '-19', '-477', '', '2400', '65.9', '309.9*3E\r\n'] 728 | 729 | VALID VSI VNAV Err(19 ft below) FPM to Target FPM to WPT HAT DTK CRS of next leg 730 | */ 731 | // - - - - - - - - - - - - - - - - - - - - - - - - - 732 | // PGRMH - Garmin Proprietary VNAV Sentence 733 | // 734 | void outputPGRMH(void) 735 | { 736 | char buf[128]; 737 | byte flags = 0; 738 | float dist; 739 | 740 | buf[0] = 0; 741 | 742 | // Valid Sentence 743 | if (VertScaleFactor > 0.1) { 744 | 745 | // NMEA Label for RMC 746 | strcpy(buf, "$PGRMH,"); 747 | 748 | // A for valid, VSI Missing - Don't have it in ARINC spec 749 | strcat(buf, "A,,"); 750 | 751 | // Calculate how far off center (VSF is full deflection distance) 752 | dist = VerticalDeviation / VertScaleFactor * 999; 753 | 754 | // Peg at +/- 100 755 | if (dist > 999) dist = 999; 756 | 757 | // Encode up.down into numbers 758 | if (VerticalDev_UD) { 759 | dist *= -1; 760 | } 761 | 762 | // Deviation above(+) or below (-) G/S 763 | appendFloat(buf, dist, 1); 764 | strcat(buf, ","); 765 | 766 | // FPM to Target and Waypoint Missing!!! No HAT either. Don't have it in ARINC??? 767 | strcat(buf, ",,2000,"); 768 | 769 | // DTK (true) 770 | appendFloat(buf, DesiredTrack, 1); 771 | strcat(buf, ","); 772 | 773 | // Calculate and attach a HEX checksum and line termination 774 | appendNMEAchecksum(buf); 775 | } else { 776 | buf[0] = 0; 777 | 778 | // Write a bogus sentence to get the Dynon HSI to release GS 779 | strcpy(buf, "$PGRMH,,,,,,,,"); 780 | appendNMEAchecksum(buf); 781 | } 782 | 783 | Serial3.write((byte *)buf, strlen(buf)); 784 | } 785 | 786 | 787 | // - - - - - - - - - - - - - - - - - - - - - - - - - 788 | void appendNMEAchecksum(char *buf) 789 | { 790 | char chkbuf[8]; 791 | int i, total; 792 | unsigned int chksum; 793 | 794 | // Calculate one byte checksum 795 | total = strlen(buf); 796 | 797 | for (i=1,chksum=0; i> 4) + 0x30; 839 | chkbuf[1] = (chksum & 0x0F) + 0x30; 840 | chkbuf[2] = 0; 841 | 842 | 843 | strcat(buf, chkbuf); 844 | 845 | // Add the line termination 846 | strcat(buf, "\r\n"); 847 | } 848 | 849 | // - - - - - - - - - - - - - - - - - - - - - - - - - 850 | void appendFloatDegrees(char *buf, float fvar) 851 | { 852 | int i,idec, ivar = int(fvar); 853 | float dec; 854 | 855 | //String-ify the Int portion 856 | itoa(ivar, &(buf[strlen(buf)]),10); 857 | 858 | // Pull the minutes into an integer and string-ify 859 | dec = abs(fvar - ivar); 860 | idec = dec = dec * 60; 861 | if (idec < 10) strcat(buf, "0"); 862 | itoa(idec, &(buf[strlen(buf)]),10); 863 | strcat(buf, "."); 864 | 865 | // Isolate the remaining decimal info, pull digits into the int side, and string-ify 866 | idec = int(dec*60); 867 | itoa(idec, &(buf[strlen(buf)]),10); 868 | } 869 | 870 | // - - - - - - - - - - - - - - - - - - - - - - - - - 871 | void appendFloat(char *buf, float fvar, int precision) 872 | { 873 | int i, idec, ivar = int(fvar); 874 | float pwrten, dec; 875 | 876 | if (precision == 0) { 877 | ivar = int(round(fvar)); 878 | itoa(ivar, &(buf[strlen(buf)]),10); 879 | } 880 | else { 881 | //String-ify the Int portion 882 | itoa(ivar, &(buf[strlen(buf)]),10); 883 | strcat(buf, "."); 884 | 885 | // Pull the decimal portion into an integer and string-ify 886 | dec = abs(fvar - ivar); 887 | for (i=0; i>13; 946 | hun = (word2 & 0x1E00)>>9; 947 | ten = (word2 & 0x01E0)>>5; 948 | one = (word2 & 0x001E)>>1; 949 | tenth = ((word2 &0x1) << 3) + ((b2 & 0xE0) >> 5); 950 | decim = tenth; 951 | dist = tho*1000+hun*100+ten*10+one+(decim/10); 952 | 953 | SerialPrintln((dist)); 954 | break; 955 | 956 | case 02: 957 | SerialPrint(("Time To Go ")); 958 | 959 | hun = (word2 & 0xE000)>>13; 960 | ten = (word2 & 0x1E00)>>9; 961 | one = (word2 & 0x01E0)>>5; 962 | tenth = (word2 & 0x001E)>>1; 963 | decim = tenth; 964 | dist = hun*100+ten*10+one+(decim/10); 965 | 966 | SerialPrintln((dist)); 967 | break; 968 | */ 969 | case 012: 970 | SerialPrint(("Ground Speed (kts) ")); 971 | 972 | tho = (word2 & 0xE000)>>13; 973 | hun = (word2 & 0x1E00)>>9; 974 | ten = (word2 & 0x01E0)>>5; 975 | one = (word2 & 0x001E)>>1; 976 | tenth = ((word2 &0x1) << 3) + ((b2 & 0xE0) >> 5); 977 | decim = tenth; 978 | GroundSpeed = tho*1000+hun*100+ten*10+one+(decim/10); 979 | 980 | SerialPrintln((GroundSpeed)); 981 | break; 982 | 983 | 984 | case 074: 985 | SerialPrint(("Data Record Header (# Recs) ")); 986 | 987 | for (i=0; i<= 20; i++) 988 | FlitePlan[i].stationtype = 0; 989 | 990 | NumWaypoints = ((word2 &0x3) << 6) + ((b2 & 0xFC) >> 2); 991 | SerialPrint(("Num Waypoints: ")); 992 | SerialPrintln((NumWaypoints)); 993 | break; 994 | 995 | 996 | case 075: 997 | SerialPrintln(("Active Waypoint From/To ")); 998 | 999 | FromWPT = (word2 & 0x7800)>>11 + ((word2 & 0x0078)>3 * 10); 1000 | ToWPT = (word2 & 0x0780)>>7 + ((((word2 &0x7) << 1) + ((b2 & 0x80) >> 7)) * 10); 1001 | break; 1002 | 1003 | 1004 | case 0100: 1005 | SerialPrint(("Selected Course ")); 1006 | SelectedCourse = angle_bnr_calc(b4, b3, b2, 3, 90); 1007 | SerialPrintln((SelectedCourse)); 1008 | break; 1009 | 1010 | case 0113: /* MSG CHECKSUM */ 1011 | //if (NumWaypoints == WaypointNumber) 1012 | 1013 | if (OnRoute) { 1014 | // Save off the Waypoint info for Flight Plan data ONLY (onRoute) 1015 | if (WaypointNumber <= 20) { 1016 | FlitePlan[WaypointNumber].stationtype = StationType; 1017 | FlitePlan[WaypointNumber].wptlatitude = WPT_Latitude; 1018 | FlitePlan[WaypointNumber].wptlatSN = WPT_Lat_SN; 1019 | FlitePlan[WaypointNumber].wptlongitude = WPT_Longitude; 1020 | FlitePlan[WaypointNumber].wptlongWE = WPT_Long_WE; 1021 | strcpy(FlitePlan[WaypointNumber].msgbuf, MsgBuf); 1022 | } 1023 | 1024 | 1025 | SerialPrint(("From WPT: ")); SerialPrint((FromWPT)); 1026 | SerialPrint((" To WPT: ")); SerialPrintln((ToWPT)); 1027 | for (i=1; i<= 20; i++) 1028 | if (FlitePlan[i].stationtype > 0) { 1029 | SerialPrint((i)); 1030 | SerialPrint((", ")); 1031 | SerialPrint((FlitePlan[i].stationtype)); 1032 | SerialPrint((": ")); 1033 | SerialPrint((FlitePlan[i].msgbuf)); 1034 | SerialPrint((", ")); 1035 | SerialPrint((FlitePlan[i].wptlatitude, 6)); 1036 | SerialPrint((FlitePlan[i].wptlatSN ? 'S':'N')); 1037 | SerialPrint((", ")); 1038 | SerialPrint((FlitePlan[i].wptlongitude, 6)); 1039 | SerialPrintln((FlitePlan[i].wptlongWE ? 'W':'E')); 1040 | } 1041 | } 1042 | break; 1043 | 1044 | case 0114: 1045 | SerialPrint(("Desired Track ")); 1046 | 1047 | DesiredTrack = angle_bnr_calc(b4, b3, b2, 3, 90); 1048 | SerialPrintln((DesiredTrack)); 1049 | break; 1050 | 1051 | case 0115: 1052 | SerialPrint(("Waypoint Bearing ")); 1053 | 1054 | WPT_Bearing = angle_bnr_calc(b4, b3, b2, 3, 90); 1055 | SerialPrintln((WPT_Bearing)); 1056 | break; 1057 | 1058 | case 0116: 1059 | SerialPrint(("Cross Track Distance (NM) ")); 1060 | 1061 | CrossTrackDist = distance_bnr_calc(b4, b3, b2, 0, 64); 1062 | 1063 | // True = Fly Right 1064 | CrossTrack_RL = b4 & 0x80; 1065 | 1066 | SerialPrintln((CrossTrackDist)); 1067 | break; 1068 | 1069 | case 0117: 1070 | Serial.print(("Vertical Deviation (ft) ")); 1071 | 1072 | // True = Fly Up 1073 | VerticalDev_UD = b4 & 0x80; 1074 | VerticalDeviation = distance_bnr_calc(b4, b3, b2, 0, 8192); 1075 | 1076 | Serial.println((VerticalDeviation)); 1077 | break; 1078 | /* 1079 | case 0121: // Disable - it spits out way too much data... 1080 | SerialPrint(("Horizontal Command (deg) ")); 1081 | if (b4 & 0x80) 1082 | SerialPrint(("Fly Left ")); 1083 | else 1084 | SerialPrint(("Fly Right ")); 1085 | 1086 | angle = distance_bnr_calc(b4, b3, b2, 1, 90); 1087 | SerialPrintln((angle)); 1088 | break; 1089 | 1090 | case 0122: 1091 | SerialPrint(("Vertical Command (deg) ")); 1092 | if (b4 & 0x80) 1093 | SerialPrint(("Fly Down ")); 1094 | else 1095 | SerialPrint(("Fly Up ")); 1096 | 1097 | // TODO: Need to parse out the flag info and stop using b2 1098 | angle = distance_bnr_calc(b4, b3, b2, 3, 90); 1099 | SerialPrintln((angle)); 1100 | break; 1101 | */ 1102 | case 0125: /* GREENWICH MEAN TIME */ 1103 | 1104 | // Parse out the time and make it ASCII HH:MM:SS 1105 | GMTBuf[0] = ((b4 & 0xE0) >> 5) + 0x30; 1106 | GMTBuf[1] = ((b4 & 0x1E) >> 1) + 0x30; 1107 | GMTBuf[2] = ((word2 & 0x01E0) >> 5) + 0x30; 1108 | GMTBuf[3] = ((word2 & 0x001E) >> 1) + 0x30; 1109 | 1110 | // Seconds are in 10ths of a minute 1111 | one = (((b3 & 0x01) << 3) + ((b2 & 0xE0) >> 5)) * 6; 1112 | GMTBuf[4] = one/10 + 0x30; 1113 | GMTBuf[5] = one%10 + 0x30; 1114 | GMTBuf[6] = 0; 1115 | 1116 | //SerialPrint("availableMemory: "); 1117 | //SerialPrintln(availableMemory()); 1118 | 1119 | break; 1120 | 1121 | case 0147: /* MAGNETIC VARIATION */ 1122 | SerialPrint(("Magnetic Variation ")); 1123 | 1124 | MagVar = angle_bnr_calc(b4, b3, b2, 3, 90); 1125 | MagVar_WE = b4 & 0x80; 1126 | 1127 | SerialPrintln((MagVar)); 1128 | break; 1129 | 1130 | case 0251: 1131 | SerialPrint(("Distance to go (nm) ")); 1132 | DistanceToGo = distance_bnr_calc(b4, b3, b2, 0, 2048); 1133 | SerialPrintln((angle)); 1134 | break; 1135 | /* 1136 | case 0252: 1137 | SerialPrint(("Time to go (minutes)")); 1138 | angle = distance_bnr_calc(b4, b3, b2, 6, 256); 1139 | SerialPrintln((angle)); 1140 | break; 1141 | */ 1142 | case 0260: 1143 | SerialPrint(("Date: ")); 1144 | 1145 | DateBuf[0] = ((b4 & 0xC0)>>6) + 0x30; 1146 | DateBuf[1] = ((b4 & 0x3C)>>2) + 0x30; 1147 | 1148 | DateBuf[2] = ((b4 & 0x02)>>1) + 0x30; 1149 | DateBuf[3] = ((word2 & 0x01E0)>>5) + 0x30; 1150 | 1151 | DateBuf[4] = ((b3 & 0x1E)>>1) + 0x30; 1152 | DateBuf[5] = ((b3 & 0x01) + ((b2 & 0xE0) >> 5)) + 0x30; 1153 | DateBuf[6] = 0; 1154 | break; 1155 | /* 1156 | case 0261: 1157 | SerialPrint(("GPS Discrete Word 1 ")); 1158 | 1159 | tho = (word2 & 0x0038)>>3; 1160 | 1161 | switch(tho) { 1162 | case 0: SerialPrintln(("No Approach Type Selected ")); break; 1163 | case 1: SerialPrintln(("LNAV ")); break; 1164 | case 2: SerialPrintln(("LNAV/VNAV ")); break; 1165 | case 4: SerialPrintln(("LP ")); break; 1166 | case 5: SerialPrintln(("LPV ")); break; 1167 | } 1168 | break; 1169 | */ 1170 | // case 0275: /* LRN STATUS WORD */ break; 1171 | 1172 | // case 0300: /* DECLINATION???? TODO */ break; 1173 | 1174 | case 0303: /* MESSAGE */ 1175 | //SerialPrint(("Station Type: "); 1176 | 1177 | StationType = ((word2 & 0x3) << 1) + ((b2 & 0x80) >> 7); 1178 | WaypointNumber = (word2 & 0x03F8) >> 3; 1179 | OnRoute = (b3 & 0x4) ? 0 : 1; 1180 | 1181 | break; 1182 | 1183 | case 0301: /* MESSAGE CHARS*/ 1184 | case 0302: 1185 | SerialPrintln(("Msg 301 or 302")); 1186 | break; 1187 | 1188 | case 0304: 1189 | MsgBuf[2] = ((b4 & 0xFE) >> 1); 1190 | MsgBuf[1] = ((word2 &0x01FC) >> 2); 1191 | MsgBuf[0] = ((word2 &0x0003) << 5) + ((b2 & 0xF8) >> 3); 1192 | 1193 | SerialPrint(("Msg 304: ")); 1194 | SerialPrintln((MsgBuf)); 1195 | break; 1196 | 1197 | case 0305: 1198 | MsgBuf[5] = ((b4 & 0xFE) >> 1); 1199 | MsgBuf[4] = ((word2 &0x01FC) >> 2); 1200 | MsgBuf[3] = ((word2 &0x0003) << 5) + ((b2 & 0xF8) >> 3); 1201 | 1202 | // Terminate string and trim trailing spaces 1203 | MsgBuf[6] = 0; 1204 | for (i=3;i<6;i++) 1205 | if (MsgBuf[i] == ' ') 1206 | MsgBuf[i] = 0; 1207 | 1208 | SerialPrint(("Msg 305: ")); 1209 | SerialPrintln((MsgBuf)); 1210 | break; 1211 | 1212 | case 0306: 1213 | case 0307: 1214 | case 0310: 1215 | case 0311: 1216 | angle = distance_bnr_calc(b4, b3, b2, -5, 90); 1217 | 1218 | if (b1 == 0306) { 1219 | WPT_Latitude = angle; 1220 | WPT_Lat_SN = b4 & 0x80; 1221 | } else if (b1 == 0310) { 1222 | PP_Latitude = angle; 1223 | PP_Lat_SN = b4 & 0x80; 1224 | } else if (b1 == 0307) { 1225 | WPT_Longitude = angle; 1226 | WPT_Long_WE = b4 & 0x80; 1227 | } else if (b1 == 0311) { 1228 | PP_Longitude = angle; 1229 | PP_Long_WE = b4 & 0x80; 1230 | } 1231 | 1232 | //if (b4 & 0x80) 1233 | // SerialPrint(("West "); 1234 | //else 1235 | // SerialPrint(("East "); 1236 | break; 1237 | /* 1238 | case 0312: 1239 | SerialPrint(("Ground Speed ")); 1240 | angle = distance_bnr_calc(b4, b3, b2, 0, 2048); 1241 | SerialPrintln((angle)); 1242 | break; 1243 | */ 1244 | case 0313: 1245 | SerialPrint(("Track Angle ")); 1246 | TrackAngle = angle_bnr_calc(b4, b3, b2, 3, 90); 1247 | SerialPrintln((TrackAngle)); 1248 | break; 1249 | /* 1250 | case 0314: 1251 | SerialPrint(("True Heading ")); 1252 | angle = angle_bnr_calc(b4, b3, b2, 0, 90); 1253 | SerialPrintln((angle)); 1254 | break; 1255 | 1256 | case 0315: 1257 | SerialPrint(("Wind Speed ")); 1258 | angle = distance_bnr_calc(b4, b3, b2, 7, 128); 1259 | SerialPrintln((angle)); 1260 | break; 1261 | 1262 | case 0316: 1263 | SerialPrint(("Wind Angle ")); 1264 | angle = angle_bnr_calc(b4, b3, b2, 3, 90); 1265 | SerialPrintln((angle)); 1266 | break; 1267 | 1268 | case 0320: 1269 | SerialPrint(("Mag Heading ")); 1270 | angle = angle_bnr_calc(b4, b3, b2, 0, 90); 1271 | SerialPrintln((angle)); 1272 | break; 1273 | 1274 | case 0321: 1275 | SerialPrint(("Drift Angle ")); 1276 | angle = angle_bnr_calc(b4, b3, b2, 3, 90); 1277 | SerialPrintln((angle)); 1278 | break; 1279 | */ 1280 | case 0326: 1281 | Serial.print(("Lateral Scale Factor (NM)")); 1282 | angle = angle_bnr_calc(b4, b3, b2, 0, 64); 1283 | LatScaleFactor = angle; 1284 | 1285 | // Set GPS Mode Range 1286 | if (LatScaleFactor <= 0.3) { 1287 | GPS_Range = GPS_APPROACH; 1288 | digitalWrite(GPS_APPROACH,HIGH); 1289 | digitalWrite(GPS_TERMINAL,LOW); 1290 | } 1291 | else if (LatScaleFactor <= 1.0) { 1292 | GPS_Range = GPS_TERMINAL; 1293 | digitalWrite(GPS_APPROACH,LOW); 1294 | digitalWrite(GPS_TERMINAL,HIGH); 1295 | } 1296 | else { 1297 | GPS_Range = GPS_ENROUTE; 1298 | digitalWrite(GPS_APPROACH,LOW); 1299 | digitalWrite(GPS_TERMINAL,LOW); 1300 | } 1301 | 1302 | Serial.println((angle)); 1303 | break; 1304 | 1305 | case 0327: 1306 | Serial.print(("Vertical Scale Factor (feet)")); 1307 | VertScaleFactor = angle_bnr_calc(b4, b3, b2, 0, 1024); 1308 | 1309 | Serial.println((VertScaleFactor)); 1310 | break; 1311 | 1312 | case 0351: 1313 | SerialPrint(("Dist to Dest(nm) ")); 1314 | SerialPrint((b2,HEX)); 1315 | SerialPrint((" ")); 1316 | DistanceToDest = distance_bnr_calc(b4, b3, b2, -3, 16384); 1317 | SerialPrintln((DistanceToDest)); 1318 | break; 1319 | 1320 | case 0352: 1321 | SerialPrint(("ETD (min) ")); 1322 | ETDest = distance_bnr_calc(b4, b3, b2, 3, 2048); 1323 | SerialPrintln((ETDest)); 1324 | break; 1325 | /* 1326 | case 0371: 1327 | SerialPrint(("EQUIPMENT IDENT CODE ")); 1328 | 1329 | tho = (word2 & 0x07E0)>>5; 1330 | 1331 | switch (tho) { 1332 | case 3: SerialPrintln(("BENDIX ")); break; 1333 | case 13: SerialPrintln(("KING ")); break; 1334 | case 24: SerialPrintln(("GARMIN ")); break; 1335 | default: SerialPrintln((tho)); break; 1336 | } 1337 | break; 1338 | 1339 | */ 1340 | default: 1341 | break; 1342 | /* 1343 | if (b4 < 16) 1344 | SerialPrint(("0")); 1345 | SerialPrint((b4, HEX)); 1346 | 1347 | SerialPrint((" ")); 1348 | if (b3 < 16) 1349 | SerialPrint(("0")); 1350 | SerialPrint((b3, HEX)); 1351 | 1352 | SerialPrint((" ")); 1353 | if (b2 < 16) 1354 | SerialPrint(("0")); 1355 | SerialPrint((b2, HEX)); 1356 | 1357 | SerialPrint((" ")); 1358 | SerialPrintln((b1, OCT)); 1359 | */ 1360 | 1361 | } 1362 | 1363 | 1364 | // When ANY ARINC data comes in do a time-check to pace the NMEA output 1365 | if (NMEA_delay < millis()) 1366 | { 1367 | // Reset the delay to 10 hz 1368 | NMEA_delay = millis() + NMEA_DELAY_MS; 1369 | 1370 | outputPGRMH(); 1371 | 1372 | // Send the minimum required NMEA every time 1373 | outputRMC(); 1374 | outputRMB(); 1375 | outputBOD(); 1376 | } 1377 | 1378 | 1379 | } 1380 | 1381 | 1382 | /************************************************************************************************* 1383 | **************************************************************************************************/ 1384 | float angle_bnr_calc( word b4, word b3, word b2, int lastbit, float bnrstart) 1385 | { 1386 | int word2; 1387 | int twos, i; 1388 | float angle, bnr; 1389 | 1390 | /* 1391 | if (b4 < 16) SerialPrint(("0"); 1392 | SerialPrint((b4, HEX); 1393 | if (b3 < 16) SerialPrint(("0"); 1394 | SerialPrint((b3, HEX); 1395 | if (b2 < 16) SerialPrint(("0"); 1396 | SerialPrint((b2, HEX); 1397 | SerialPrint((" "); 1398 | */ 1399 | // save off the two's complement flag and then consolidate and shift the value so we can use it 1400 | twos = b4 & 0x80; 1401 | word2 = (((b4&0x7F) << 8) + b3); 1402 | 1403 | // It's either a 2's complement of (360 - Track Angle) else its the positive angle 0 to < 180 degrees 1404 | // if (twos) { 1405 | // word2 = word2 ^ 0xFFFFFFFF; 1406 | // } 1407 | 1408 | // calculate the angle based on BNR math 1409 | angle = 0; bnr = bnrstart; 1410 | 1411 | // Now put initial binary value into a float and iterate from hi-bit to lo-bit, 1412 | // dividing the float/2 each time and accumulating the result 1413 | 1414 | for (i=14; i>=lastbit; i--) { 1415 | if (bitRead(word2, i)) 1416 | angle += bnr; 1417 | 1418 | bnr /= 2.0; 1419 | } 1420 | 1421 | if (twos) 1422 | angle = 180 + angle; 1423 | 1424 | return angle; 1425 | } 1426 | 1427 | 1428 | 1429 | /************************************************************************************************* 1430 | **************************************************************************************************/ 1431 | float distance_bnr_calc( word b4, word b3, word b2, int lastbit, float bnrstart) 1432 | { 1433 | int word2, xbit=0; 1434 | int sense, i; 1435 | float dist, bnr; 1436 | /* 1437 | if (b4 < 16) SerialPrint(("0")); 1438 | SerialPrint((b4, HEX)); 1439 | if (b3 < 16) SerialPrint(("0")); 1440 | SerialPrint((b3, HEX)); 1441 | if (b2 < 16) SerialPrint(("0")); 1442 | SerialPrint((b2, HEX)); 1443 | SerialPrint((" ")); 1444 | */ 1445 | // save off the sense flag and then mask it off 1446 | sense = b4 & 0x80; 1447 | word2 = (((b4&0x7F) << 8) + b3); 1448 | 1449 | if (sense) { 1450 | word2 = word2 ^ 0xFFFF; 1451 | } 1452 | 1453 | // calculate the angle based on BNR math 1454 | dist = 0; bnr = bnrstart; 1455 | 1456 | // Do we need the b2 bits? 1457 | if (lastbit < 0) { 1458 | xbit = abs(lastbit); 1459 | lastbit = 0; 1460 | } 1461 | 1462 | // Now put initial binary value into a float and iterate from hi-bit to lo-bit, 1463 | // dividing the float/2 each time and accumulating the result 1464 | for (i=14; i>=lastbit; i--) { 1465 | if (bitRead(word2, i)) 1466 | dist += bnr; 1467 | 1468 | bnr /= 2.0; 1469 | } 1470 | 1471 | // If we are using extended resolution continue into the b2 word 1472 | if (xbit > 0) { 1473 | for (i=7; i>(7-xbit); i--) { 1474 | if (bitRead(b2, i)) 1475 | dist += bnr; 1476 | 1477 | bnr /= 2.0; 1478 | } 1479 | } 1480 | 1481 | return dist; 1482 | } 1483 | 1484 | 1485 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1486 | static int stream_pos = 0; 1487 | static char outstr[128], instrm[128]; 1488 | 1489 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1490 | void pad_int_to_string(char *out, int val, int width) 1491 | { 1492 | int i, vwidth; 1493 | 1494 | if (val) 1495 | vwidth = log10(val) + 1; 1496 | else 1497 | vwidth = 1; 1498 | 1499 | 1500 | // Pad total width with zeros 1501 | for (i=0; i start-transmit character 1541 | outstr[spos++] = char(2); 1542 | 1543 | 1544 | // Save altitude sign and zero it to terminate the IAS string properly for itoa() 1545 | char altsign = instrm[24]; 1546 | instrm[24] = 0; 1547 | 1548 | // IAS - Dynon sends M/S - convert to Knots 1549 | strcpy(&(outstr[spos]), "ZA"); 1550 | spos+= 2; 1551 | 1552 | float ias = atoi(&(instrm[20])) * 0.19438445; 1553 | pad_int_to_string(&(outstr[spos]), ias, 3); 1554 | spos+= 5; 1555 | 1556 | 1557 | // Save the VSI sign for later and to zero the end of the altitude string for itoa() 1558 | altsign = instrm[29]; 1559 | instrm[29] = 0; 1560 | 1561 | // low bit of pos[47] determines which info is in EFIS data 1562 | if (instrm[46] != '0') { 1563 | // PALT - Dynon sends Meters - convert to 10's of feet 1564 | strcpy(&(outstr[spos]), "ZD"); 1565 | spos+= 2; 1566 | outstr[spos++] = altsign; 1567 | 1568 | float alt = atoi(&(instrm[25])) * .32808399; 1569 | pad_int_to_string(&(outstr[spos]), alt, 4); 1570 | spos+= 6; 1571 | } else { 1572 | } 1573 | 1574 | // low bit of pos[47] determines which info is in EFIS data 1575 | if (instrm[46] == '0') { 1576 | // Rate of Turn +/- (deg / sec) 1577 | strcpy(&(outstr[spos]), "ZJ"); 1578 | outstr[spos+2] = altsign; 1579 | strncpy(&(outstr[spos+3]), &(instrm[30]), 2); 1580 | strcpy(&(outstr[spos+5]), "\r\n"); 1581 | spos+= 7; 1582 | } else { 1583 | // Vertical SPD 1584 | strcpy(&(outstr[spos]), "ZK"); 1585 | 1586 | // write the sign and zero the end of the number for atoi() 1587 | outstr[spos+2] = altsign; 1588 | instrm[33] = 0; 1589 | int vsi = atoi(&(instrm[30])) * 6; 1590 | 1591 | pad_int_to_string(&(outstr[spos+3]), vsi, 3); 1592 | spos+= 8; 1593 | } 1594 | 1595 | // Heading 1596 | strcpy(&(outstr[spos]), "ZL"); 1597 | strncpy(&(outstr[spos+2]), &(instrm[17]), 3); 1598 | strcpy(&(outstr[spos+5]), "\r\n"); 1599 | spos+= 7; 1600 | 1601 | // ERR 1602 | strcpy(&(outstr[spos]), "ZQ000\r\n"); 1603 | spos+= 7; 1604 | 1605 | // Indicated Altitude (Baro corrected) 1606 | //strcpy(&(outstr[spos]), "Ga+0100\r\n"); 1607 | //spos+= 9; 1608 | 1609 | // Calculate one byte checksum 1610 | for (i=chksum=0; i end-transmit character 1624 | outstr[spos++] = char(3); 1625 | //strcpy(&outstr[spos++], "0x03", 1); 1626 | 1627 | //Serial.write((byte *)outstr, spos); 1628 | 1629 | // Send out to GPS via Tx1 1630 | Serial1.write((byte *)outstr, spos); 1631 | 1632 | } 1633 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1634 | 1635 | void process_efis_data() 1636 | { 1637 | byte inbyte; 1638 | int num; 1639 | 1640 | // limit read to whats there or what our buffer can handle. No blocking please! 1641 | instrm[stream_pos++] = inbyte = Serial2.read(); 1642 | 1643 | //SerialPrint((inbyte); 1644 | if (inbyte == 0x0A) { 1645 | // Serial.print("EFIS data length: "); Serial.println(stream_pos); 1646 | 1647 | // Look for the correct line length in lieu of a CRC - seems to weed out the cruft 1648 | if (stream_pos == 53) 1649 | convert_efis_to_fadc(); 1650 | 1651 | // If we found a LF reset the buffer to capture the next one. 1652 | stream_pos = 0; 1653 | } 1654 | 1655 | if (stream_pos > 100) { 1656 | // Serial.println(("in stream too long - no 0x0A detected")); 1657 | stream_pos = 0; 1658 | } 1659 | 1660 | 1661 | } 1662 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1663 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1664 | 1665 | void process_user_command() 1666 | { 1667 | byte command = ' '; 1668 | command = Serial.read(); 1669 | 1670 | 1671 | if (command >= '0' && command <= '9') 1672 | { 1673 | Test_Rate = (command - 0x2F)*50; 1674 | } 1675 | 1676 | switch (command) 1677 | { 1678 | case 'S': 1679 | { 1680 | Test_Output ^= 1; 1681 | Test_Rate = 1000; 1682 | break; 1683 | } 1684 | case 'l': 1685 | { 1686 | controlword1 = controlword1 | NOTSLFTST; 1687 | resetARINC(); 1688 | break; 1689 | } 1690 | case 'L': 1691 | { 1692 | controlword1 = controlword1 & ~NOTSLFTST; 1693 | resetARINC(); 1694 | break; 1695 | } 1696 | case 'P': 1697 | { 1698 | controlword1 = controlword1 | PAREN; 1699 | resetARINC(); 1700 | break; 1701 | } 1702 | case 'p': 1703 | { 1704 | controlword1 = controlword1 & ~PAREN; 1705 | resetARINC(); 1706 | break; 1707 | } 1708 | case 'r': 1709 | { 1710 | controlword2 = controlword2 | RXLO; 1711 | resetARINC(); 1712 | break; 1713 | } 1714 | case 'R': 1715 | { 1716 | controlword2 = controlword2 & ~RXLO; 1717 | resetARINC(); 1718 | break; 1719 | } 1720 | case 't': 1721 | { 1722 | controlword2 = controlword2 | TXLO; 1723 | resetARINC(); 1724 | break; 1725 | } 1726 | case 'T': 1727 | { 1728 | controlword2 = controlword2 & ~TXLO; 1729 | resetARINC(); 1730 | break; 1731 | } 1732 | default: 1733 | break; 1734 | } 1735 | } 1736 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1737 | ////////////////////////////////////////////////////////////////////////////////////////////////// 1738 | void loop() 1739 | { 1740 | int txReady; 1741 | 1742 | SerialPrintln(("Send L/l for Loopback/normal, R/r for receiver speed HIGH/low, P/p for Parity ENABLE/disable")); 1743 | 1744 | resetARINC(); 1745 | while (true) 1746 | { 1747 | if (Serial.available()) { 1748 | process_user_command(); 1749 | } 1750 | 1751 | if (Serial2.available()) { 1752 | process_efis_data(); 1753 | } 1754 | 1755 | 1756 | // TEST Output 1757 | 1758 | 1759 | //if (Test_Output && (NMEA_delay < millis())) 1760 | if (0) { 1761 | // Reset the delay to 10 hz 1762 | NMEA_delay = millis() + Test_Rate; 1763 | 1764 | SelectedCourse = Test_VNAV + 100; 1765 | VerticalDeviation = Test_VNAV; 1766 | CrossTrackDist = abs(Test_VNAV); 1767 | CrossTrack_RL = (Test_VNAV < 0) ? 1 : 0; 1768 | Test_VNAV++; 1769 | 1770 | if (Test_VNAV > 100) Test_VNAV = -100; 1771 | 1772 | VertScaleFactor = 100; 1773 | LatScaleFactor = 100; 1774 | 1775 | outputPGRMH(); 1776 | outputRMC(); 1777 | outputRMB(); 1778 | outputBOD(); 1779 | 1780 | if (CrossTrack_RL) { 1781 | digitalWrite(Annunciate_TRM,HIGH); 1782 | digitalWrite(Annunciate_APR,LOW); 1783 | } else { 1784 | digitalWrite(Annunciate_TRM,LOW); 1785 | digitalWrite(Annunciate_APR,HIGH); 1786 | } 1787 | 1788 | //outputHSI(); 1789 | //outputOBS(); 1790 | //outputActiveVOR(); 1791 | //outputSL30Misc(); 1792 | } 1793 | 1794 | /* Someday we should really play with ARINC 429 output as well. 1795 | 1796 | txReady = digitalRead(a429TXR_pin); 1797 | if (txReady==HIGH) // the transmitter is not busy now so we can send 1798 | { 1799 | // txARINC(); // a canned test word 1800 | } 1801 | */ 1802 | rxARINC(); 1803 | } 1804 | } 1805 | 1806 | 1807 | -------------------------------------------------------------------------------- /avrio.h: -------------------------------------------------------------------------------- 1 | /************************************************************************************************ 2 | * avrio.h 3 | * AVRIO defines a set of i/o primitives that work on AVR pins. 4 | * 5 | * vi:ts=4 6 | * 7 | * Copyright (C) 2009,2010 Bill Perry. (bperrybap@opensource.billsworld.billandterrie.com) 8 | * 9 | * This file is included as part of the Arduino GLCD library. 10 | * 11 | * This version of avrio.h is licensed only for use in the Arduino software environment 12 | * with the GLCD Library. 13 | * 14 | * You can download a version of AVRIO that can be used with other code from: 15 | * http://www.opensource.billsworld.billandterrie.com/avr/avrio 16 | * 17 | * GLCD is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU Lesser General Public License as published by 19 | * the Free Software Foundation, either version 2.1 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * GLCD is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU Lesser General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU Lesser General Public License 28 | * along with GLCD. If not, see . 29 | * 30 | * 31 | ************************************************************************************************ 32 | * 33 | * 34 | * These primitives are for setting/reading digital levels on the pins. 35 | * 36 | * When used with the GCC optimization, the final code generated will be the 37 | * smallest amount of AVR instructions possible to set/clear or read the desired i/o bits. 38 | * 39 | * It introduces a new AVR s/w i/o concept. 40 | * It is wrapped around the concept of an "avrpin". 41 | * An avrpin is a compile-time token that can be used to locate a particular avrpin. 42 | * It is different than the bitmask scheme used by the standard AVR C headers or 43 | * the simple integer scheme as currently used by Arduino. 44 | * avrpin has encoded into it: the port, A, B, C, etc, as well as the bit information 45 | * within that port. 46 | * 47 | * What is intentionally not encoded in it is the actual register type 48 | * of choice: DDR, PIN, or PORT. 49 | * Therefore, the register type of choice must be indicated to the primitives using 50 | * the correspending values: AVRIO_DDRREG, AVRIO_PINREG, AVRIO_PORTREG 51 | * 52 | * 53 | * Special Note: While avrpin format is very different from arduino pin#s, 54 | * in arduino environments, avrio will map arduino pin#s to avrpins 55 | * on the fly so arduino users can use arduino pin#s with the primitives. 56 | * This capability requires the use a mapping macro digitalPinToPortReg() 57 | * which should be provided by an inluding an arduino header file. 58 | * That header file *MUST* be included before including this header. 59 | * 60 | * The pin parameter used in all the primitives will automaticaly adapt to different environments and 61 | * suports multiple different style defintions. 62 | * 63 | * In native AVR (non arduino) enviroments, the pin parameter should be specified using the 64 | * pin defintions near the end of this header file. 65 | * These pin definitions allow directly specifying a specific AVR pin using a PIN_Pb syntax. 66 | * where Pb represents a PORT and a pin#. 67 | * This means to specify port D bit 3 would be PIN_D3 68 | * 69 | * For the time being, naked constants can also be used for pins on AVR ports A-F. 70 | * So PORTD pin 3 could also be specified by avr pin 0xd3 71 | * 72 | * Arduino users may use either arduino pin#s, or the raw PIN_Pb style naming. 73 | * 74 | * 75 | * Primitives: 76 | * 77 | * bitval = avrio_ReadBit(regtyp, pin) 78 | * byteval = avrio_Read8Bits(regtyp, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 79 | * byteval = avrio_ReadReg(regtyp, avrport) 80 | * 81 | * avrio_WriteBit(regtyp, pin, bitval) 82 | * avrio_Write8Bits(regtyp, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, data) 83 | * avrio_WriteReg(regtyp, avrport, byteval) 84 | * 85 | *------------ 86 | * 87 | * The following avrio primitives are convenience macros: 88 | * They simply call the above primitives with an implied register type. 89 | * PinMode writes to DDR dir 1 = output, dir 0 = input 90 | * ReadPin reads from PIN 91 | * WritePin writes to PORT 92 | * 93 | * avrio_PinMode(pin, dir) 94 | * avrio_PinMode8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, dir) 95 | * 96 | * bitval = avrio_ReadPin(pin) 97 | * byteval = avrio_Read8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 98 | * 99 | * avrio_WritePin(pin, bitval) 100 | * avrio_Write8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, byteval) 101 | * 102 | *------------ 103 | * 104 | * The following primitives are provideed as "convenience" to be similar to the Arduino pin 105 | * primitives: 106 | * 107 | * avrio_pinMode(pin, dir) 108 | * avrio_pinMode8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, dir) 109 | * 110 | * avrio_digitalWrite(pin, pinval) 111 | * avrio_digitalWritepin(pin, pinval) 112 | * avrio_digitalWrite8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7, byteval) 113 | * 114 | * 115 | * pinval = avrio_digitalRead(pin) 116 | * pinval = avrio_digitalReadPin(pin) 117 | * byteval = avrio_digitalRead8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 118 | *---------------------------------------------------------------------------------- 119 | * NOTE: 120 | * For a full description of the calling sequence for each primitive 121 | * see the comments below for each primitive. 122 | * 123 | * 124 | *---------------------------------------------------------------------------------- 125 | * 126 | * WARNING: 127 | * 128 | * These routines are based on gcc inline functions and are currently designed 129 | * for arguments that are constants. If non constants are used, terrible code will 130 | * be generated. However, with constants, the code will generate the smallest possible 131 | * code including using using CBI/SBI instructions when possible. 132 | * 133 | * These primitives do not do any type of handholding or altering of the 134 | * of the port configuration bits. Bits are written to the desired registers. 135 | * No more, no less. 136 | * 137 | * 138 | * To support the arduino environment, a mapping from arduino pin#s is automatically performed. 139 | * This will be done if the macro digitalPinToPortReg() exists. 140 | * 141 | * 142 | */ 143 | /************************************************************************************************/ 144 | 145 | #ifndef _AVRIO_AVRIO_ 146 | #define _AVRIO_AVRIO_ 147 | 148 | #define AVRIO_PORTA 0xa 149 | #define AVRIO_PORTB 0xb 150 | #define AVRIO_PORTC 0xc 151 | #define AVRIO_PORTD 0xd 152 | #define AVRIO_PORTE 0xe 153 | #define AVRIO_PORTF 0xf 154 | 155 | #define AVRIO_PORTG 0x10 156 | #define AVRIO_PORTH 0x11 157 | #define AVRIO_PORTI 0x12 158 | #define AVRIO_PORTJ 0x13 159 | #define AVRIO_PORTK 0x14 160 | #define AVRIO_PORTL 0x15 161 | 162 | #define AVRIO_DDRREG 1 163 | #define AVRIO_PORTREG 2 164 | #define AVRIO_PINREG 3 165 | 166 | typedef uint16_t avrpin_t; /* This must be uint16_t to support ports larger than F */ 167 | 168 | /* 169 | * Generates an avrpin # 170 | * 171 | * The avrpin port values start at 0xa for port A and go up. 172 | * The port value is in the upper 12 bits of the 16 bit avrpin value. 173 | * The bit value is encoded into the lower 4 bits. 174 | * 175 | * But because the port numbers start at 0xa, there 160 avrpin #s 176 | * below the first valid encoded avrpin value. These numbers are 177 | * used/reserved for private numbering spaces. 178 | * This is wheter the arduino numbers reside. 179 | * So when a pin number less than lowest valid avrpin# is used, avrio will 180 | * need a private mapping function to mapp from that private numbering space 181 | * the the avrpin numbering space. 182 | * 183 | * This is how mapping is done from the arduino pin #s to avrio avrpin#s. 184 | * 185 | * 186 | * The current encoding also allows the use of naked constants for 187 | * ports a-f. 188 | * 189 | * So for talking to port D pin 2 the avrpin # would be 0xd2 190 | * That said, it is recommended to use the PIN_Pb defines, 191 | * for future compatibility should the encoding change. 192 | * so rather than use 0xd2, it is recommended to use PIN_D2 193 | */ 194 | 195 | #define AVRIO_PIN(avrport, avrbit) ((avrport << 4) | avrbit) 196 | 197 | #define AVRIO_PIN2AVRPORT(pin) (AVRIO_PIN2AVRPIN(pin) >> 4) 198 | #define AVRIO_PIN2AVRBIT(pin) (AVRIO_PIN2AVRPIN(pin) & 0xf) 199 | #define AVRIO_PIN2AVRBITMASK(pin) _BV((AVRIO_PIN2AVRBIT(pin))) 200 | 201 | 202 | 203 | /* 204 | * Atomagically detect Arduino pin mapping macros. 205 | * This allows automatic mapping of arduino pin#s to avrpin #s. 206 | */ 207 | 208 | #ifdef digitalPinToPortReg 209 | static inline avrpin_t avrio_arduino_pin2avrpin(uint8_t pin) __attribute__((always_inline)); 210 | 211 | #define AVRIO_PIN2AVRPIN(pin) ((pin < AVRIO_PIN(AVRIO_PORTA, 0)) ? avrio_arduino_pin2avrpin(pin) : pin) 212 | 213 | avrpin_t 214 | avrio_arduino_pin2avrpin(uint8_t pin) 215 | { 216 | uint8_t avrbit = digitalPinToBit(pin); 217 | volatile void *avrportaddr = digitalPinToPortReg(pin); 218 | 219 | 220 | #ifdef PORTA 221 | if(avrportaddr == &PORTA) 222 | return(AVRIO_PIN(AVRIO_PORTA, avrbit)); 223 | #endif 224 | #ifdef PORTB 225 | if(avrportaddr == &PORTB) 226 | return(AVRIO_PIN(AVRIO_PORTB, avrbit)); 227 | #endif 228 | #ifdef PORTC 229 | if(avrportaddr == &PORTC) 230 | return(AVRIO_PIN(AVRIO_PORTC, avrbit)); 231 | #endif 232 | #ifdef PORTD 233 | if(avrportaddr == &PORTD) 234 | return(AVRIO_PIN(AVRIO_PORTD, avrbit)); 235 | #endif 236 | #ifdef PORTE 237 | if(avrportaddr == &PORTE) 238 | return(AVRIO_PIN(AVRIO_PORTE, avrbit)); 239 | #endif 240 | #ifdef PORTF 241 | if(avrportaddr == &PORTF) 242 | return(AVRIO_PIN(AVRIO_PORTF, avrbit)); 243 | #endif 244 | #ifdef PORTG 245 | if(avrportaddr == &PORTG) 246 | return(AVRIO_PIN(AVRIO_PORTG, avrbit)); 247 | #endif 248 | #ifdef PORTH 249 | if(avrportaddr == &PORTH) 250 | return(AVRIO_PIN(AVRIO_PORTH, avrbit)); 251 | #endif 252 | #ifdef PORTI 253 | if(avrportaddr == &PORTI) 254 | return(AVRIO_PIN(AVRIO_PORTI, avrbit)); 255 | #endif 256 | #ifdef PORTJ 257 | if(avrportaddr == &PORTJ) 258 | return(AVRIO_PIN(AVRIO_PORTJ, avrbit)); 259 | #endif 260 | #ifdef PORTK 261 | if(avrportaddr == &PORTK) 262 | return(AVRIO_PIN(AVRIO_PORTK, avrbit)); 263 | #endif 264 | #ifdef PORTL 265 | if(avrportaddr == &PORTL) 266 | return(AVRIO_PIN(AVRIO_PORTL, avrbit)); 267 | #endif 268 | return(-1); 269 | } 270 | 271 | #endif 272 | 273 | 274 | /* 275 | * if there is no custom PIN2AVRPIN mapping macro, then define the default 276 | * a mapping function which assumes pins are in avrpin # format. 277 | * 278 | * About errors with incorrect pin formats: 279 | * 280 | * Because the mapping is primarily done with the C preprocessor macros, there isn't much 281 | * that can be done inside a function type macro when the parameter is out of range. 282 | * 283 | * Currently, if we receive an pin value that is not in avrpin format and cannot be mapped, 284 | * no error is reported and no code is generated. 285 | * 286 | */ 287 | 288 | 289 | 290 | #ifndef AVRIO_PIN2AVRPIN 291 | #define AVRIO_PIN2AVRPIN(pin) pin 292 | 293 | #endif 294 | 295 | 296 | /************************************************************************************************ 297 | * 298 | * Convenience primitives start here 299 | * 300 | ************************************************************************************************/ 301 | 302 | /* 303 | * Define the avrio convenience primitives. 304 | */ 305 | #define avrio_PinMode(pin, dir) avrio_WriteBit(AVRIO_DDRREG, pin, dir) 306 | #define avrio_PinMode8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) \ 307 | avrio_Write8Bits(AVRIO_DDRREG, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 308 | 309 | #define avrio_ReadPin(pin) avrio_ReadBit(AVRIO_PINREG, pin) 310 | #define avrio_Read8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) \ 311 | avrio_Read8Bits(AVRIO_PINREG, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 312 | 313 | #define avrio_WritePin(pin, data) avrio_WriteBit(AVRIO_PORTREG, pin, data) 314 | #define avrio_Write8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) \ 315 | avrio_Write8Bits(AVRIO_PORTREG, pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 316 | 317 | 318 | /* 319 | * Define the Arduino "compatible" primitives 320 | */ 321 | #define avrio_digitalRead(pin) avrio_ReadPin(pin) 322 | #define avrio_digitalReadPin(pin) avrio_ReadPin(pin) 323 | #define avrio_digitalRead8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) \ 324 | avrio_Read8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 325 | 326 | #define avrio_digitalWrite(pin, data) avrio_WritePin(pin, data) 327 | #define avrio_digitalWritePin(pin, data) avrio_WritePin(pin, data) 328 | #define avrio_digitalWrite8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) \ 329 | avrio_Write8Pins(pin0, pin1, pin2, pin3, pin4, pin5, pin6, pin7) 330 | 331 | 332 | #define avrio_pinMode(pin, dir) avrio_PinMode(pin, dir) 333 | #define avrio_pinMode8Pins(pin, dir) avrio_PinMode8Pins(pin, dir) 334 | 335 | 336 | /************************************************************************************************ 337 | * 338 | * User primitives start here 339 | * 340 | ************************************************************************************************/ 341 | 342 | /************************************************************************ 343 | * PRIMITIAVE: avrio_WriteBit - set a bit/pin value 344 | * 345 | * SYNOPSIS: 346 | * void avrio_WriteBit(uint8_t regtyp, avrpin_t avrpin, uint8_t val); 347 | * 348 | * INPUT PARAMETERS: 349 | * uint8_t regtyp; 350 | * specifies the register type, either DDR, PORT or PIN. 351 | * Must be one of: AVRIO_DDRREG, AVRIO_PORTREG, AVRIO_PINREG 352 | * 353 | * avrpin_t avrpin; 354 | * This value is an "avrpin" value *not* a simple pin value. 355 | * (see notes below for details) 356 | * 357 | * uint8_t val; 358 | * If 0 bit is set to 0, if non zero, bit is set to 1. 359 | * 360 | * 361 | * OUTPUT PARAMETERS: 362 | * (none) 363 | * 364 | * DESCRIPTION: 365 | * This function sets a value to a i/o register bit or a pin. The desired register 366 | * type (DDR, PORT, or PIN) can be specified. 367 | * 368 | * The avrpin paramter will automaticaly adapt to different environments and 369 | * suports multiple different style defintions. 370 | * 371 | * In non arduino enviroments, this value should be specified using the 372 | * pin defintions below. Direct pin values can be specified using a 373 | * PIN_Pb definition. This means to speccify port D bit 3 would be PIN_D3 374 | * 375 | * Arduino users may use either arduino pin#s, or the PIN_Pb style naming. 376 | * 377 | * 378 | * RETURN VALUE: 379 | * (none) 380 | * 381 | * NOTES/WARNINGS: 382 | * This function can only be used with constants. If any argument is not a constant, 383 | * terrible code that is very large will result. 384 | * 385 | * If arduno pin#s are used for avrpin and if the header that defines the macro: 386 | * digitalPinToPortReg() is not included, incorrect/invalid code will silently be generated. 387 | * 388 | * 389 | * 390 | * SEE ALSO: 391 | * avrio_Write8Bits 392 | * 393 | ************************************************************************/ 394 | 395 | static inline void avrio_WriteBit(uint8_t regtyp, avrpin_t pin, uint8_t val) __attribute__((always_inline)); 396 | 397 | void 398 | avrio_WriteBit(uint8_t regtyp, avrpin_t avrpin, uint8_t val) 399 | { 400 | uint8_t avrbitmask = AVRIO_PIN2AVRBITMASK(avrpin); 401 | uint8_t avrport = AVRIO_PIN2AVRPORT(avrpin); 402 | 403 | if (val) { 404 | if (avrport == AVRIO_PORTA) { 405 | #ifdef PORTA 406 | if(regtyp == AVRIO_DDRREG) 407 | DDRA |= avrbitmask; 408 | else if ( regtyp == AVRIO_PINREG) 409 | PINA |= avrbitmask; 410 | else if ( regtyp == AVRIO_PORTREG) 411 | PORTA |= avrbitmask; 412 | #endif 413 | #ifdef PORTB 414 | } else if (avrport == AVRIO_PORTB) { 415 | if(regtyp == AVRIO_DDRREG) 416 | DDRB |= avrbitmask; 417 | else if ( regtyp == AVRIO_PINREG) 418 | PINB |= avrbitmask; 419 | else if ( regtyp == AVRIO_PORTREG) 420 | PORTB |= avrbitmask; 421 | #endif 422 | #ifdef PORTC 423 | } else if (avrport == AVRIO_PORTC) { 424 | if(regtyp == AVRIO_DDRREG) 425 | DDRC |= avrbitmask; 426 | else if ( regtyp == AVRIO_PINREG) 427 | PINC |= avrbitmask; 428 | else if ( regtyp == AVRIO_PORTREG) 429 | PORTC |= avrbitmask; 430 | #endif 431 | #ifdef PORTD 432 | } else if (avrport == AVRIO_PORTD) { 433 | if(regtyp == AVRIO_DDRREG) 434 | DDRD |= avrbitmask; 435 | else if ( regtyp == AVRIO_PINREG) 436 | PIND |= avrbitmask; 437 | else if ( regtyp == AVRIO_PORTREG) 438 | PORTD |= avrbitmask; 439 | #endif 440 | #ifdef PORTE 441 | } else if (avrport == AVRIO_PORTE) { 442 | if(regtyp == AVRIO_DDRREG) 443 | DDRE |= avrbitmask; 444 | else if ( regtyp == AVRIO_PINREG) 445 | PINE |= avrbitmask; 446 | else if ( regtyp == AVRIO_PORTREG) 447 | PORTE |= avrbitmask; 448 | #endif 449 | #ifdef PORTF 450 | } else if (avrport == AVRIO_PORTF) { 451 | if(regtyp == AVRIO_DDRREG) 452 | DDRF |= avrbitmask; 453 | else if ( regtyp == AVRIO_PINREG) 454 | PINF |= avrbitmask; 455 | else if ( regtyp == AVRIO_PORTREG) 456 | PORTF |= avrbitmask; 457 | #endif 458 | #ifdef PORTG 459 | } else if (avrport == AVRIO_PORTG) { 460 | if(regtyp == AVRIO_DDRREG) 461 | DDRG |= avrbitmask; 462 | else if ( regtyp == AVRIO_PINREG) 463 | PING |= avrbitmask; 464 | else if ( regtyp == AVRIO_PORTREG) 465 | PORTG |= avrbitmask; 466 | #endif 467 | #ifdef PORTH 468 | } else if (avrport == AVRIO_PORTH) { 469 | if(regtyp == AVRIO_DDRREG) 470 | DDRH |= avrbitmask; 471 | else if ( regtyp == AVRIO_PINREG) 472 | PINH |= avrbitmask; 473 | else if ( regtyp == AVRIO_PORTREG) 474 | PORTH |= avrbitmask; 475 | #endif 476 | #ifdef PORTI 477 | } else if (avrport == AVRIO_PORTI) { 478 | if(regtyp == AVRIO_DDRREG) 479 | DDRI |= avrbitmask; 480 | else if ( regtyp == AVRIO_PINREG) 481 | PINI |= avrbitmask; 482 | else if ( regtyp == AVRIO_PORTREG) 483 | PORTI |= avrbitmask; 484 | #endif 485 | #ifdef PORTJ 486 | } else if (avrport == AVRIO_PORTJ) { 487 | if(regtyp == AVRIO_DDRREG) 488 | DDRJ |= avrbitmask; 489 | else if ( regtyp == AVRIO_PINREG) 490 | PINJ |= avrbitmask; 491 | else if ( regtyp == AVRIO_PORTREG) 492 | PORTJ |= avrbitmask; 493 | #endif 494 | #ifdef PORTK 495 | } else if (avrport == AVRIO_PORTK) { 496 | if(regtyp == AVRIO_DDRREG) 497 | DDRK |= avrbitmask; 498 | else if ( regtyp == AVRIO_PINREG) 499 | PINK |= avrbitmask; 500 | else if ( regtyp == AVRIO_PORTREG) 501 | PORTK |= avrbitmask; 502 | #endif 503 | #ifdef PORTL 504 | } else if (avrport == AVRIO_PORTL) { 505 | if(regtyp == AVRIO_DDRREG) 506 | DDRL |= avrbitmask; 507 | else if ( regtyp == AVRIO_PINREG) 508 | PINL |= avrbitmask; 509 | else if ( regtyp == AVRIO_PORTREG) 510 | PORTL |= avrbitmask; 511 | #endif 512 | } else { 513 | } 514 | } else { 515 | if (avrport == AVRIO_PORTA) { 516 | #ifdef PORTA 517 | if(regtyp == AVRIO_DDRREG) 518 | DDRA &= ~avrbitmask; 519 | else if ( regtyp == AVRIO_PINREG) 520 | PINA &= ~avrbitmask; 521 | else if ( regtyp == AVRIO_PORTREG) 522 | PORTA &= ~avrbitmask; 523 | #endif 524 | #ifdef PORTB 525 | } else if (avrport == AVRIO_PORTB) { 526 | if(regtyp == AVRIO_DDRREG) 527 | DDRB &= ~avrbitmask; 528 | else if ( regtyp == AVRIO_PINREG) 529 | PINB &= ~avrbitmask; 530 | else if ( regtyp == AVRIO_PORTREG) 531 | PORTB &= ~avrbitmask; 532 | #endif 533 | #ifdef PORTC 534 | } else if (avrport == AVRIO_PORTC) { 535 | if(regtyp == AVRIO_DDRREG) 536 | DDRC &= ~avrbitmask; 537 | else if ( regtyp == AVRIO_PINREG) 538 | PINC &= ~avrbitmask; 539 | else if ( regtyp == AVRIO_PORTREG) 540 | PORTC &= ~avrbitmask; 541 | #endif 542 | #ifdef PORTD 543 | } else if (avrport == AVRIO_PORTD) { 544 | if(regtyp == AVRIO_DDRREG) 545 | DDRD &= ~avrbitmask; 546 | else if ( regtyp == AVRIO_PINREG) 547 | PIND &= ~avrbitmask; 548 | else if ( regtyp == AVRIO_PORTREG) 549 | PORTD &= ~avrbitmask; 550 | #endif 551 | #ifdef PORTE 552 | } else if (avrport == AVRIO_PORTE) { 553 | if(regtyp == AVRIO_DDRREG) 554 | DDRE &= ~avrbitmask; 555 | else if ( regtyp == AVRIO_PINREG) 556 | PINE &= ~avrbitmask; 557 | else if ( regtyp == AVRIO_PORTREG) 558 | PORTE &= ~avrbitmask; 559 | #endif 560 | #ifdef PORTF 561 | } else if (avrport == AVRIO_PORTF) { 562 | if(regtyp == AVRIO_DDRREG) 563 | DDRF &= ~avrbitmask; 564 | else if ( regtyp == AVRIO_PINREG) 565 | PINF &= ~avrbitmask; 566 | else if ( regtyp == AVRIO_PORTREG) 567 | PORTF &= ~avrbitmask; 568 | #endif 569 | #ifdef PORTG 570 | } else if (avrport == AVRIO_PORTG) { 571 | if(regtyp == AVRIO_DDRREG) 572 | DDRG &= ~avrbitmask; 573 | else if ( regtyp == AVRIO_PINREG) 574 | PING &= ~avrbitmask; 575 | else if ( regtyp == AVRIO_PORTREG) 576 | PORTG &= ~avrbitmask; 577 | #endif 578 | #ifdef PORTH 579 | } else if (avrport == AVRIO_PORTH) { 580 | if(regtyp == AVRIO_DDRREG) 581 | DDRH &= ~avrbitmask; 582 | else if ( regtyp == AVRIO_PINREG) 583 | PINH &= ~avrbitmask; 584 | else if ( regtyp == AVRIO_PORTREG) 585 | PORTH &= ~avrbitmask; 586 | #endif 587 | #ifdef PORTI 588 | } else if (avrport == AVRIO_PORTI) { 589 | if(regtyp == AVRIO_DDRREG) 590 | DDRI &= ~avrbitmask; 591 | else if ( regtyp == AVRIO_PINREG) 592 | PINI &= ~avrbitmask; 593 | else if ( regtyp == AVRIO_PORTREG) 594 | PORTI &= ~avrbitmask; 595 | #endif 596 | #ifdef PORTJ 597 | } else if (avrport == AVRIO_PORTJ) { 598 | if(regtyp == AVRIO_DDRREG) 599 | DDRJ &= ~avrbitmask; 600 | else if ( regtyp == AVRIO_PINREG) 601 | PINJ &= ~avrbitmask; 602 | else if ( regtyp == AVRIO_PORTREG) 603 | PORTJ &= ~avrbitmask; 604 | #endif 605 | #ifdef PORTK 606 | } else if (avrport == AVRIO_PORTK) { 607 | if(regtyp == AVRIO_DDRREG) 608 | DDRK &= ~avrbitmask; 609 | else if ( regtyp == AVRIO_PINREG) 610 | PINK &= ~avrbitmask; 611 | else if ( regtyp == AVRIO_PORTREG) 612 | PORTK &= ~avrbitmask; 613 | #endif 614 | #ifdef PORTL 615 | } else if (avrport == AVRIO_PORTL) { 616 | if(regtyp == AVRIO_DDRREG) 617 | DDRL &= ~avrbitmask; 618 | else if ( regtyp == AVRIO_PINREG) 619 | PINL &= ~avrbitmask; 620 | else if ( regtyp == AVRIO_PORTREG) 621 | PORTL &= ~avrbitmask; 622 | #endif 623 | } else { 624 | } 625 | } 626 | } 627 | 628 | 629 | /* 630 | * Internal Register write function. 631 | * This is not a defined primitive 632 | */ 633 | static inline void avrio_WriteReg(uint8_t regtyp, uint8_t avrport, uint8_t data) __attribute__((always_inline)); 634 | 635 | void 636 | avrio_WriteReg(uint8_t regtyp, uint8_t avrport, uint8_t data) 637 | { 638 | if (avrport == AVRIO_PORTA) { 639 | #ifdef PORTA 640 | if(regtyp == AVRIO_DDRREG) 641 | DDRA = data; 642 | else if (regtyp == AVRIO_PINREG) 643 | PINA = data; 644 | else if (regtyp == AVRIO_PORTREG) 645 | PORTA = data; 646 | #endif 647 | #ifdef PORTB 648 | } else if (avrport == AVRIO_PORTB) { 649 | if(regtyp == AVRIO_DDRREG) 650 | DDRB = data; 651 | else if (regtyp == AVRIO_PINREG) 652 | PINB = data; 653 | else if (regtyp == AVRIO_PORTREG) 654 | PORTB = data; 655 | #endif 656 | #ifdef PORTC 657 | } else if (avrport == AVRIO_PORTC) { 658 | if(regtyp == AVRIO_DDRREG) 659 | DDRC = data; 660 | else if (regtyp == AVRIO_PINREG) 661 | PINC = data; 662 | else if (regtyp == AVRIO_PORTREG) 663 | PORTC = data; 664 | #endif 665 | #ifdef PORTD 666 | } else if (avrport == AVRIO_PORTD) { 667 | if(regtyp == AVRIO_DDRREG) 668 | DDRD = data; 669 | else if (regtyp == AVRIO_PINREG) 670 | PIND = data; 671 | else if (regtyp == AVRIO_PORTREG) 672 | PORTD = data; 673 | #endif 674 | #ifdef PORTE 675 | } else if (avrport == AVRIO_PORTE) { 676 | if(regtyp == AVRIO_DDRREG) 677 | DDRE = data; 678 | else if (regtyp == AVRIO_PINREG) 679 | PINE = data; 680 | else if (regtyp == AVRIO_PORTREG) 681 | PORTE = data; 682 | #endif 683 | #ifdef PORTF 684 | } else if (avrport == AVRIO_PORTF) { 685 | if(regtyp == AVRIO_DDRREG) 686 | DDRF = data; 687 | else if (regtyp == AVRIO_PINREG) 688 | PINF = data; 689 | else if (regtyp == AVRIO_PORTREG) 690 | PORTF = data; 691 | #endif 692 | #ifdef PORTG 693 | } else if (avrport == AVRIO_PORTG) { 694 | if(regtyp == AVRIO_DDRREG) 695 | DDRG = data; 696 | else if (regtyp == AVRIO_PINREG) 697 | PING = data; 698 | else if (regtyp == AVRIO_PORTREG) 699 | PORTG = data; 700 | #endif 701 | #ifdef PORTH 702 | } else if (avrport == AVRIO_PORTH) { 703 | if(regtyp == AVRIO_DDRREG) 704 | DDRH = data; 705 | else if (regtyp == AVRIO_PINREG) 706 | PINH = data; 707 | else if (regtyp == AVRIO_PORTREG) 708 | PORTH = data; 709 | #endif 710 | #ifdef PORTI 711 | } else if (avrport == AVRIO_PORTI) { 712 | if(regtyp == AVRIO_DDRREG) 713 | DDRI = data; 714 | else if (regtyp == AVRIO_PINREG) 715 | PINI = data; 716 | else if (regtyp == AVRIO_PORTREG) 717 | PORTI = data; 718 | #endif 719 | #ifdef PORTJ 720 | } else if (avrport == AVRIO_PORTJ) { 721 | if(regtyp == AVRIO_DDRREG) 722 | DDRJ = data; 723 | else if (regtyp == AVRIO_PINREG) 724 | PINJ = data; 725 | else if (regtyp == AVRIO_PORTREG) 726 | PORTJ = data; 727 | #endif 728 | #ifdef PORTK 729 | } else if (avrport == AVRIO_PORTK) { 730 | if(regtyp == AVRIO_DDRREG) 731 | DDRK = data; 732 | else if (regtyp == AVRIO_PINREG) 733 | PINK = data; 734 | else if (regtyp == AVRIO_PORTREG) 735 | PORTK = data; 736 | #endif 737 | #ifdef PORTL 738 | } else if (avrport == AVRIO_PORTL) { 739 | if(regtyp == AVRIO_DDRREG) 740 | DDRL = data; 741 | else if (regtyp == AVRIO_PINREG) 742 | PINL = data; 743 | else if (regtyp == AVRIO_PORTREG) 744 | PORTL = data; 745 | #endif 746 | } else { 747 | } 748 | } 749 | 750 | /* 751 | * Internal function not really meant for external use 752 | */ 753 | 754 | static inline uint8_t avrio_ReadReg(uint8_t regtyp, uint8_t avrport) __attribute__((always_inline)); 755 | 756 | uint8_t 757 | avrio_ReadReg(uint8_t regtyp, uint8_t avrport) 758 | { 759 | #ifdef PORTA 760 | if (avrport == AVRIO_PORTA) 761 | { 762 | if(regtyp == AVRIO_DDRREG) 763 | return(DDRA); 764 | else if ( regtyp == AVRIO_PINREG) 765 | return(PINA); 766 | else if ( regtyp == AVRIO_PORTREG) 767 | return(PORTA); 768 | } 769 | #endif 770 | #ifdef PORTB 771 | if (avrport == AVRIO_PORTB) 772 | { 773 | if(regtyp == AVRIO_DDRREG) 774 | return(DDRB); 775 | else if ( regtyp == AVRIO_PINREG) 776 | return(PINB); 777 | else if ( regtyp == AVRIO_PORTREG) 778 | return(PORTB); 779 | } 780 | #endif 781 | #ifdef PORTC 782 | if (avrport == AVRIO_PORTC) 783 | { 784 | if(regtyp == AVRIO_DDRREG) 785 | return(DDRC); 786 | else if ( regtyp == AVRIO_PINREG) 787 | return(PINC); 788 | else if ( regtyp == AVRIO_PORTREG) 789 | return(PORTC); 790 | } 791 | #endif 792 | #ifdef PORTD 793 | if (avrport == AVRIO_PORTD) 794 | { 795 | if(regtyp == AVRIO_DDRREG) 796 | return(DDRD); 797 | else if ( regtyp == AVRIO_PINREG) 798 | return(PIND); 799 | else if ( regtyp == AVRIO_PORTREG) 800 | return(PORTD); 801 | } 802 | #endif 803 | #ifdef PORTE 804 | if (avrport == AVRIO_PORTE) 805 | { 806 | if(regtyp == AVRIO_DDRREG) 807 | return(DDRE); 808 | else if ( regtyp == AVRIO_PINREG) 809 | return(PINE); 810 | else if ( regtyp == AVRIO_PORTREG) 811 | return(PORTE); 812 | } 813 | #endif 814 | #ifdef PORTF 815 | if (avrport == AVRIO_PORTF) 816 | { 817 | if(regtyp == AVRIO_DDRREG) 818 | return(DDRF); 819 | else if ( regtyp == AVRIO_PINREG) 820 | return(PINF); 821 | else if ( regtyp == AVRIO_PORTREG) 822 | return(PORTF); 823 | } 824 | #endif 825 | #ifdef PORTG 826 | if (avrport == AVRIO_PORTG) 827 | { 828 | if(regtyp == AVRIO_DDRREG) 829 | return(DDRG); 830 | else if ( regtyp == AVRIO_PINREG) 831 | return(PING); 832 | else if ( regtyp == AVRIO_PORTREG) 833 | return(PORTG); 834 | } 835 | #endif 836 | #ifdef PORTH 837 | if (avrport == AVRIO_PORTH) 838 | { 839 | if(regtyp == AVRIO_DDRREG) 840 | return(DDRH); 841 | else if ( regtyp == AVRIO_PINREG) 842 | return(PINH); 843 | else if ( regtyp == AVRIO_PORTREG) 844 | return(PORTH); 845 | } 846 | #endif 847 | #ifdef PORTI 848 | if (avrport == AVRIO_PORTI) 849 | { 850 | if(regtyp == AVRIO_DDRREG) 851 | return(DDRI); 852 | else if ( regtyp == AVRIO_PINREG) 853 | return(PINI); 854 | else if ( regtyp == AVRIO_PORTREG) 855 | return(PORTI); 856 | } 857 | #endif 858 | #ifdef PORTJ 859 | if (avrport == AVRIO_PORTJ) 860 | { 861 | if(regtyp == AVRIO_DDRREG) 862 | return(DDRJ); 863 | else if ( regtyp == AVRIO_PINREG) 864 | return(PINJ); 865 | else if ( regtyp == AVRIO_PORTREG) 866 | return(PORTJ); 867 | } 868 | #endif 869 | #ifdef PORTK 870 | if (avrport == AVRIO_PORTK) 871 | { 872 | if(regtyp == AVRIO_DDRREG) 873 | return(DDRK); 874 | else if ( regtyp == AVRIO_PINREG) 875 | return(PINK); 876 | else if ( regtyp == AVRIO_PORTREG) 877 | return(PORTK); 878 | } 879 | #endif 880 | #ifdef PORTL 881 | if (avrport == AVRIO_PORTL) 882 | { 883 | if(regtyp == AVRIO_DDRREG) 884 | return(DDRL); 885 | else if ( regtyp == AVRIO_PINREG) 886 | return(PINL); 887 | else if ( regtyp == AVRIO_PORTREG) 888 | return(PORTL); 889 | } 890 | #endif 891 | return(0); /* not sure how to handle bad port values */ 892 | } 893 | 894 | /************************************************************************ 895 | * PRIMITIAVE: avrio_ReadBit - Read a bit/pin value 896 | * 897 | * SYNOPSIS: 898 | * uint8_t bitval = avrio_ReadBit(uint8_t regtyp, avrpin_t avrpin); 899 | * 900 | * INPUT PARAMETERS: 901 | * uint8_t regtyp; 902 | * specifies the register type, either DDR, PORT or PIN. 903 | * Must be one of: AVRIO_DDRREG, AVRIO_PORTREG, AVRIO_PINREG 904 | * 905 | * avrpin_t avrpin; 906 | * This value is an "avrpin" value *not* a simple pin value. 907 | * (see notes below for details) 908 | * 909 | * 910 | * OUTPUT PARAMETERS: 911 | * (none) 912 | * 913 | * DESCRIPTION: 914 | * This function tests to see if a bit in a i/o register or a pin is set. 915 | * The desired register type (DDR, PORT, or PIN) can be specified. 916 | * 917 | * The return value is 0 if the bit is not set. If the bit is set, 918 | * the return value will be a non zero value. 919 | * 920 | * The avrpin paramter will automaticaly adapt to different environments and 921 | * suports multiple different style defintions. 922 | * 923 | * In non arduino enviroments, this value should be specified using the 924 | * pin defintions below. Direct pin values can be specified using a 925 | * PIN_Pb definition. This means to specify port D bit 3 would be PIN_D3 926 | * 927 | * Arduino users may use either arduino pin#s, or the PIN_Pb style naming. 928 | * 929 | * 930 | * RETURN VALUE: 931 | * 0 bit not set 932 | * non-0 bit is set (Note that this is not 1 it is "non 0") 933 | * 934 | * NOTES/WARNINGS: 935 | * 936 | * This function can only be used with constants. If any argument is not a constant, 937 | * terrible code that is very large will result. 938 | * 939 | * If arduno pin#s are used for avrpin and if the header that defines the macro: 940 | * digitalPinToPortReg() is not included, incorrect/invalid code will silently be generated. 941 | * 942 | * 943 | * 944 | * SEE ALSO: 945 | * avrio_Read8Bits 946 | * 947 | ************************************************************************/ 948 | 949 | static inline uint8_t avrio_ReadBit(uint8_t regtyp, avrpin_t avrpin) __attribute__((always_inline)); 950 | 951 | uint8_t 952 | avrio_ReadBit(uint8_t regtyp, avrpin_t avrpin) 953 | { 954 | uint8_t avrbitmask = AVRIO_PIN2AVRBITMASK(avrpin); 955 | uint8_t avrport = AVRIO_PIN2AVRPORT(avrpin); 956 | 957 | #ifdef PORTA 958 | if (avrport == AVRIO_PORTA) 959 | { 960 | if(regtyp == AVRIO_DDRREG) 961 | return(DDRA & avrbitmask); 962 | else if ( regtyp == AVRIO_PINREG) 963 | return(PINA & avrbitmask); 964 | else if ( regtyp == AVRIO_PORTREG) 965 | return(PORTA & avrbitmask); 966 | } 967 | #endif 968 | #ifdef PORTB 969 | if (avrport == AVRIO_PORTB) 970 | { 971 | if(regtyp == AVRIO_DDRREG) 972 | return(DDRB & avrbitmask); 973 | else if ( regtyp == AVRIO_PINREG) 974 | return(PINB & avrbitmask); 975 | else if ( regtyp == AVRIO_PORTREG) 976 | return(PORTB & avrbitmask); 977 | } 978 | #endif 979 | #ifdef PORTC 980 | if (avrport == AVRIO_PORTC) 981 | { 982 | if(regtyp == AVRIO_DDRREG) 983 | return(DDRC & avrbitmask); 984 | else if ( regtyp == AVRIO_PINREG) 985 | return(PINC & avrbitmask); 986 | else if ( regtyp == AVRIO_PORTREG) 987 | return(PORTC & avrbitmask); 988 | } 989 | #endif 990 | #ifdef PORTD 991 | if (avrport == AVRIO_PORTD) 992 | { 993 | if(regtyp == AVRIO_DDRREG) 994 | return(DDRD & avrbitmask); 995 | else if ( regtyp == AVRIO_PINREG) 996 | return(PIND & avrbitmask); 997 | else if ( regtyp == AVRIO_PORTREG) 998 | return(PORTD & avrbitmask); 999 | } 1000 | #endif 1001 | #ifdef PORTE 1002 | if (avrport == AVRIO_PORTE) 1003 | { 1004 | if(regtyp == AVRIO_DDRREG) 1005 | return(DDRE & avrbitmask); 1006 | else if ( regtyp == AVRIO_PINREG) 1007 | return(PINE & avrbitmask); 1008 | else if ( regtyp == AVRIO_PORTREG) 1009 | return(PORTE & avrbitmask); 1010 | } 1011 | #endif 1012 | #ifdef PORTF 1013 | if (avrport == AVRIO_PORTF) 1014 | { 1015 | if(regtyp == AVRIO_DDRREG) 1016 | return(DDRF & avrbitmask); 1017 | else if ( regtyp == AVRIO_PINREG) 1018 | return(PINF & avrbitmask); 1019 | else if ( regtyp == AVRIO_PORTREG) 1020 | return(PORTF & avrbitmask); 1021 | } 1022 | #endif 1023 | #ifdef PORTG 1024 | if (avrport == AVRIO_PORTG) 1025 | { 1026 | if(regtyp == AVRIO_DDRREG) 1027 | return(DDRG & avrbitmask); 1028 | else if ( regtyp == AVRIO_PINREG) 1029 | return(PING & avrbitmask); 1030 | else if ( regtyp == AVRIO_PORTREG) 1031 | return(PORTG & avrbitmask); 1032 | } 1033 | #endif 1034 | #ifdef PORTH 1035 | if (avrport == AVRIO_PORTH) 1036 | { 1037 | if(regtyp == AVRIO_DDRREG) 1038 | return(DDRH & avrbitmask); 1039 | else if ( regtyp == AVRIO_PINREG) 1040 | return(PINH & avrbitmask); 1041 | else if ( regtyp == AVRIO_PORTREG) 1042 | return(PORTH & avrbitmask); 1043 | } 1044 | #endif 1045 | #ifdef PORTI 1046 | if (avrport == AVRIO_PORTI) 1047 | { 1048 | if(regtyp == AVRIO_DDRREG) 1049 | return(DDRI & avrbitmask); 1050 | else if ( regtyp == AVRIO_PINREG) 1051 | return(PINI & avrbitmask); 1052 | else if ( regtyp == AVRIO_PORTREG) 1053 | return(PORTI & avrbitmask); 1054 | } 1055 | #endif 1056 | #ifdef PORTJ 1057 | if (avrport == AVRIO_PORTJ) 1058 | { 1059 | if(regtyp == AVRIO_DDRREG) 1060 | return(DDRJ & avrbitmask); 1061 | else if ( regtyp == AVRIO_PINREG) 1062 | return(PINJ & avrbitmask); 1063 | else if ( regtyp == AVRIO_PORTREG) 1064 | return(PORTJ & avrbitmask); 1065 | } 1066 | #endif 1067 | #ifdef PORTK 1068 | if (avrport == AVRIO_PORTK) 1069 | { 1070 | if(regtyp == AVRIO_DDRREG) 1071 | return(DDRK & avrbitmask); 1072 | else if ( regtyp == AVRIO_PINREG) 1073 | return(PINK & avrbitmask); 1074 | else if ( regtyp == AVRIO_PORTREG) 1075 | return(PORTK & avrbitmask); 1076 | } 1077 | #endif 1078 | #ifdef PORTL 1079 | if (avrport == AVRIO_PORTL) 1080 | { 1081 | if(regtyp == AVRIO_DDRREG) 1082 | return(DDRL & avrbitmask); 1083 | else if ( regtyp == AVRIO_PINREG) 1084 | return(PINL & avrbitmask); 1085 | else if ( regtyp == AVRIO_PORTREG) 1086 | return(PORTL & avrbitmask); 1087 | } 1088 | #endif 1089 | return(0); /* not sure how to handle bad port values */ 1090 | } 1091 | 1092 | 1093 | /* 1094 | * 1095 | * The routines below are for moving multiple bits into AVR pins. 1096 | * This is a somewhat complex task as to keep things easy for configuration, 1097 | * there are no limits placed on pins or ports. 1098 | * So the code must figure out which pins are together on the same port to 1099 | * optimize the bit twiddling. If enough bits are together it will use 1100 | * full bytes or nibbles. 1101 | * 1102 | * NOTE:WARNING: This function is currently only desiged for constant 1103 | * arguments. Do not use it with variables. 1104 | * 1105 | * The following are the 6 possible 1106 | * combinations of 8 bit i/o configurations: 1107 | * 1108 | * DATA pins AVR bits Access method 1109 | * 1) p0-p7 d0-d7 on same port 8bit byte 1110 | * 1111 | * 2) p0-p3 on d0-d3 of port 4 bit nibble 1112 | * p4-p7 scattered bits individual i/o 1113 | * 1114 | * 3) p0-p3 on d4-d7 of port 4 bit nibble 1115 | * p4-p7 scattered bits individual i/o 1116 | * 1117 | * 4) p0-p3 scattered bits individual i/o 1118 | * p4-p7 on d0-d3 of port 4 bit nibble 1119 | * 1120 | * 5) p0-p3 scattered bits individual i/o 1121 | * p4-p7 on d4-d7 of port 4 bit nibble 1122 | * 1123 | * 6) p0-p3 on d4-d7 of port 4 bit nibble 1124 | * p4-p7 on d0-d3 of port 4 bit nibble 1125 | * 1126 | * NOTE: in this nibble swap case the code does not check to 1127 | * see if the ports are the same. 1128 | * 1129 | * 1130 | * 7) p0-p3 scattered bits individual i/o 1131 | * p4-p7 scattered bits individual i/o 1132 | * 1133 | * 1134 | * Code will automatically detect when data pins are adjacent, ordered and on 1135 | * the same ports or within nibbles. It will automatically use the best 1136 | * possible method to set the pins. 1137 | * To get 8 bit mode, all 8 pins much match up with all 8 AVR bits 1138 | * on a single port. p0->d0, p1->d1, etc... 1139 | * 1140 | * To get a nibble mode, 4 pins of a nibble must align with 4 bits 1141 | * on a AVR port. Nibbles don't have to match. i.e. code can swap nibbles. 1142 | * i.e. p0-p3 matched with d0-d3 or p0-p3 matched with d4-d7 1143 | * likewise on the upper bits: p4-p7 matched with d0-d3 or p4-p7 matched with d4-d7. 1144 | * 1145 | * If nothing is aligned, the code will drop down to individual bit i/o. 1146 | * 1147 | * The port & nibble detection works because of the sparse avrpin numbering scheme. 1148 | * The lower 4 bits of an avrpin # is the avr port bit #. 1149 | * For example, A0-A7 is valid but A8-AF is not used. 1150 | * 1151 | * By knowing this, it is possible to see if avrpins are on the same port. 1152 | * So avrpins that are numerically adjacent are gurarnteed to be on the same AVR port. 1153 | * 1154 | */ 1155 | 1156 | 1157 | /* 1158 | * Defines to simplify conditionals for checking for the above 6 configuration combinations. 1159 | */ 1160 | 1161 | /* 1162 | * Figures out if all 8 pins are contiguous and on same port for 8 bit mode 1163 | */ 1164 | 1165 | #define AVRDATA_8BIT(p0, p1, p2, p3, p4, p5, p6, p7) \ 1166 | (AVRIO_PIN2AVRPIN(p0) + 1 == AVRIO_PIN2AVRPIN(p1) \ 1167 | && AVRIO_PIN2AVRPIN(p1) + 1 == AVRIO_PIN2AVRPIN(p2) \ 1168 | && AVRIO_PIN2AVRPIN(p2) + 1 == AVRIO_PIN2AVRPIN(p3) \ 1169 | && AVRIO_PIN2AVRPIN(p3) + 1 == AVRIO_PIN2AVRPIN(p4) \ 1170 | && AVRIO_PIN2AVRPIN(p4) + 1 == AVRIO_PIN2AVRPIN(p5) \ 1171 | && AVRIO_PIN2AVRPIN(p5) + 1 == AVRIO_PIN2AVRPIN(p6) \ 1172 | && AVRIO_PIN2AVRPIN(p6) + 1 == AVRIO_PIN2AVRPIN(p7) \ 1173 | ) 1174 | 1175 | /* 1176 | * figures out if 4 avrpins map to bits D0-D3 on an AVR port (lo nibble) 1177 | */ 1178 | #define AVRDATA_4BITLO(p0, p1, p2, p3) \ 1179 | (AVRIO_PIN2AVRPIN(p0) + 1 == AVRIO_PIN2AVRPIN(p1) \ 1180 | && AVRIO_PIN2AVRPIN(p1) + 1 == AVRIO_PIN2AVRPIN(p2) \ 1181 | && AVRIO_PIN2AVRPIN(p2) + 1 == AVRIO_PIN2AVRPIN(p3) \ 1182 | && AVRIO_PIN2AVRBIT(p0) == 0 \ 1183 | ) 1184 | 1185 | /* 1186 | * figures out if 4 avrpins map to bits D4-D7 on an AVR port 1187 | */ 1188 | #define AVRDATA_4BITHI(p0, p1, p2, p3) \ 1189 | (AVRIO_PIN2AVRPIN(p0) + 1 == AVRIO_PIN2AVRPIN(p1) \ 1190 | && AVRIO_PIN2AVRPIN(p1) + 1 == AVRIO_PIN2AVRPIN(p2) \ 1191 | && AVRIO_PIN2AVRPIN(p2) + 1 == AVRIO_PIN2AVRPIN(p3) \ 1192 | && AVRIO_PIN2AVRBIT(p3) == 7 \ 1193 | ) 1194 | 1195 | 1196 | 1197 | /************************************************************************ 1198 | * PRIMITIAVE: avrio_Write8Bits - write 8 bits to i/o register(s) 1199 | * 1200 | * SYNOPSIS: 1201 | * void avrio_Write8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1202 | * avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7, uint8_t data) 1203 | * 1204 | * INPUT PARAMETERS: 1205 | * uint8_t regtyp; 1206 | * specifies the register type, either DDR, PORT or PIN. 1207 | * Must be one of: AVRIO_DDRREG, AVRIO_PORTREG, AVRIO_PINREG 1208 | * 1209 | * avrpin_t p0; 1210 | * avrpin_t p1; 1211 | * avrpin_t p2; 1212 | * avrpin_t p3; 1213 | * avrpin_t p4; 1214 | * avrpin_t p5; 1215 | * avrpin_t p6; 1216 | * avrpin_t p7; 1217 | * specifies the 8 bits/pins to of where to write the 8 bit data. 1218 | * (see notes below for details) 1219 | * 1220 | * uint8_t data; 1221 | * The 8 bit value to be written. 1222 | * 1223 | * 1224 | * OUTPUT PARAMETERS: 1225 | * (none) 1226 | * 1227 | * DESCRIPTION: 1228 | * This function sets 8 i/o register bit/pin values from a single 8 bit byte. The desired register 1229 | * type (DDR, PORT, or PIN) can be specified. 1230 | * 1231 | * Since each "pin" parameter is an avrpin, each pin can independently specify which AVR port to use. 1232 | * 1233 | * The code will automatically figure out the best possible method of writing to the 1234 | * register bits. If bits/pins are adjacent on the same port and in the proper sequence, 1235 | * the code will use 4 bit nibbles or even a single 8 bit byte write. 1236 | * If nothing is aligned, then individual SBI/CBI instructions will be used. 1237 | * 1238 | * The avrpin paramters will automaticaly adapt to different environments and 1239 | * suports multiple different style defintions. 1240 | * 1241 | * In non arduino enviroments, this value should be specified using the 1242 | * pin defintions below. Direct pin values can be specified using a 1243 | * PIN_Pb definition. This means to speccify port D bit 3 would be PIN_D3 1244 | * 1245 | * Arduino users may use either arduino pin#s, or the PIN_Pb style naming. 1246 | * 1247 | * 1248 | * 1249 | * RETURN VALUE: 1250 | * (none) 1251 | * 1252 | * NOTES/WARNINGS: 1253 | * This function can only be used with constants. If any argument is not a constant, 1254 | * terrible code that is very large will result. 1255 | * 1256 | * If arduno pin#s are used for avrpin and if the header that defines the macro: 1257 | * digitalPinToPortReg() is not included, incorrect/invalid code will silently be generated. 1258 | * 1259 | * 1260 | * 1261 | * SEE ALSO: 1262 | * avrio_WriteReg 1263 | * avrio_Write8Bits 1264 | * 1265 | ************************************************************************/ 1266 | 1267 | static inline void avrio_Write8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1268 | avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7, uint8_t data) __attribute__((always_inline)); 1269 | 1270 | 1271 | void 1272 | avrio_Write8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1273 | avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7, uint8_t data) 1274 | { 1275 | 1276 | if(AVRDATA_8BIT(p0, p1, p2, p3, p4, p5, p6, p7)) 1277 | { 1278 | /* 1279 | * data0-data7 on same port; full 8 bit mode 1280 | */ 1281 | avrio_WriteReg(regtyp, AVRIO_PIN2AVRPORT(p0), data); 1282 | } 1283 | else 1284 | { 1285 | #ifndef AVRIO_NO4BIT 1286 | if(AVRDATA_4BITLO(p0, p1, p2, p3)) 1287 | { 1288 | 1289 | /* 1290 | * data0-data3 on same LO nibble 1291 | */ 1292 | 1293 | avrio_WriteReg(regtyp, AVRIO_PIN2AVRPORT(p0), 1294 | (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p0)) & 0xf0) | (data & 0x0f)); 1295 | 1296 | } 1297 | else if(AVRDATA_4BITHI(p0, p1, p2, p3)) 1298 | { 1299 | /* 1300 | * data0-data3 on same HI nibble 1301 | */ 1302 | 1303 | avrio_WriteReg(regtyp, AVRIO_PIN2AVRPORT(p0), 1304 | (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p0)) & 0x0f) | (uint8_t)(data << 4)); 1305 | 1306 | } 1307 | else 1308 | #endif 1309 | { 1310 | /* 1311 | * data0-data3 require BIT i/o 1312 | */ 1313 | 1314 | /* 1315 | * While this sequence looks odd, it is actaully fewer cycles 1316 | * to slam all the bits to 0, then selectively turn on the needed 1317 | * bits, rather than use a if/else to set & clear each bit. 1318 | */ 1319 | 1320 | avrio_WriteBit(regtyp, p0, 0); 1321 | avrio_WriteBit(regtyp, p1, 0); 1322 | avrio_WriteBit(regtyp, p2, 0); 1323 | avrio_WriteBit(regtyp, p3, 0); 1324 | 1325 | if(data & _BV(0)) avrio_WriteBit(regtyp, p0, 1); 1326 | if(data & _BV(1)) avrio_WriteBit(regtyp, p1, 1); 1327 | if(data & _BV(2)) avrio_WriteBit(regtyp, p2, 1); 1328 | if(data & _BV(3)) avrio_WriteBit(regtyp, p3, 1); 1329 | 1330 | } 1331 | 1332 | #ifndef AVRIO_NO4BIT 1333 | 1334 | if(AVRDATA_4BITLO(p4, p5, p6, p7)) 1335 | { 1336 | /* 1337 | * data4-data7 on same LOW nibble 1338 | */ 1339 | 1340 | avrio_WriteReg(regtyp, AVRIO_PIN2AVRPORT(p4), 1341 | (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p4)) & 0xf0) | (data >> 4)); 1342 | } 1343 | else if(AVRDATA_4BITHI(p4, p5, p6, p7)) 1344 | { 1345 | /* 1346 | * data4-data7 on same HIGH nibble 1347 | */ 1348 | 1349 | avrio_WriteReg(regtyp, AVRIO_PIN2AVRPORT(p4), 1350 | (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p4)) & 0x0f) | (data & 0xf0)); 1351 | } 1352 | else 1353 | #endif 1354 | { 1355 | /* 1356 | * data4-data7 require BIT i/o 1357 | */ 1358 | 1359 | /* 1360 | * While this sequence looks odd, it is actaully fewer cycles 1361 | * to slam all the bits to 0, then selectively turn on the needed 1362 | * bits, rather than use a if/else to set & clear each bit. 1363 | */ 1364 | 1365 | avrio_WriteBit(regtyp, p4, 0); 1366 | avrio_WriteBit(regtyp, p5, 0); 1367 | avrio_WriteBit(regtyp, p6, 0); 1368 | avrio_WriteBit(regtyp, p7, 0); 1369 | 1370 | if(data & _BV(4)) avrio_WriteBit(regtyp, p4, 1); 1371 | if(data & _BV(5)) avrio_WriteBit(regtyp, p5, 1); 1372 | if(data & _BV(6)) avrio_WriteBit(regtyp, p6, 1); 1373 | if(data & _BV(7)) avrio_WriteBit(regtyp, p7, 1); 1374 | } 1375 | } 1376 | } 1377 | 1378 | /************************************************************************ 1379 | * PRIMITIAVE: avrio_Read8Bits - read 8 bits from i/o register(s) 1380 | * 1381 | * SYNOPSIS: 1382 | * uint8_t byteval = avrio_Write8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1383 | * avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7, uint8_t data) 1384 | * 1385 | * INPUT PARAMETERS: 1386 | * uint8_t regtyp; 1387 | * specifies the register type, either DDR, PORT or PIN. 1388 | * Must be one of: AVRIO_DDRREG, AVRIO_PORTREG, AVRIO_PINREG 1389 | * 1390 | * avrpin_t p0; 1391 | * avrpin_t p1; 1392 | * avrpin_t p2; 1393 | * avrpin_t p3; 1394 | * avrpin_t p4; 1395 | * avrpin_t p5; 1396 | * avrpin_t p6; 1397 | * avrpin_t p7; 1398 | * specifies the 8 bits/pins to of where to write the 8 bit data. 1399 | * (see notes below for details) 1400 | * 1401 | * 1402 | * OUTPUT PARAMETERS: 1403 | * (none) 1404 | * 1405 | * DESCRIPTION: 1406 | * This function reads 8 i/o register bit/pin values and composes them into a single 8 bit byte. 1407 | * The desired register type (DDR, PORT, or PIN) can be specified. 1408 | * 1409 | * Since each "pin" parameter is an avrpin, each pin can independently specify which AVR port to use. 1410 | * 1411 | * The code will automatically figure out the best possible method of reading the 1412 | * register bits. If bits/pins are adjacent on the same port and in the proper sequence, 1413 | * the code will use 4 bit nibbles or even a single 8 bit byte read. 1414 | * If nothing is aligned, then individual bit test instructions will be used. 1415 | * 1416 | * The avrpin paramters will automaticaly adapt to different environments and 1417 | * suports multiple different style defintions. 1418 | * 1419 | * In non arduino enviroments, this value should be specified using the 1420 | * pin defintions below. Direct pin values can be specified using a 1421 | * PIN_Pb definition. This means to speccify port D bit 3 would be PIN_D3 1422 | * 1423 | * Arduino users may use either arduino pin#s, or the PIN_Pb style naming. 1424 | * 1425 | * 1426 | * 1427 | * RETURN VALUE: 1428 | * 8 bit data value 1429 | * 1430 | * NOTES/WARNINGS: 1431 | * This function can only be used with constants. If any argument is not a constant, 1432 | * terrible code that is very large will result. 1433 | * 1434 | * If arduno pin#s are used for avrpin and if the header that defines the macro: 1435 | * digitalPinToPortReg() is not included, incorrect/invalid code will silently be generated. 1436 | * 1437 | * 1438 | * 1439 | * SEE ALSO: 1440 | * avrio_ReadBit 1441 | * 1442 | ************************************************************************/ 1443 | static inline uint8_t 1444 | avrio_Read8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1445 | avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7) __attribute__((always_inline)); 1446 | 1447 | uint8_t 1448 | avrio_Read8Bits(uint8_t regtyp, avrpin_t p0, avrpin_t p1, avrpin_t p2, avrpin_t p3, 1449 | avrpin_t p4, avrpin_t p5, avrpin_t p6, avrpin_t p7) 1450 | { 1451 | uint8_t data; 1452 | 1453 | if(AVRDATA_8BIT(p0, p1, p2, p3, p4, p5, p6, p7)) 1454 | { 1455 | /* 1456 | * Full 8 bit mode 1457 | */ 1458 | 1459 | data = avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p0)); 1460 | } 1461 | else 1462 | { 1463 | data = 0; 1464 | #ifndef AVRIO_NO4BIT 1465 | if(AVRDATA_4BITLO(p0, p1, p2, p3)) 1466 | { 1467 | /* 1468 | * data0-data3 on same LOW nibble 1469 | */ 1470 | 1471 | data |= (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p0)) & 0xf); 1472 | 1473 | } 1474 | else if(AVRDATA_4BITHI(p0, p1, p2, p3)) 1475 | { 1476 | /* 1477 | * data0-data3 on same HIGH nibble 1478 | */ 1479 | 1480 | data |= ((avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p0))) >> 4); 1481 | 1482 | } 1483 | else 1484 | #endif 1485 | { 1486 | /* 1487 | * data0-data3 require BIT i/o 1488 | */ 1489 | 1490 | if(avrio_ReadBit(regtyp, p0)) data |= _BV(0); 1491 | if(avrio_ReadBit(regtyp, p1)) data |= _BV(1); 1492 | if(avrio_ReadBit(regtyp, p2)) data |= _BV(2); 1493 | if(avrio_ReadBit(regtyp, p3)) data |= _BV(3); 1494 | 1495 | } 1496 | 1497 | #ifndef AVRIO_NO4BIT 1498 | if(AVRDATA_4BITLO(p4, p5, p6, p7)) 1499 | { 1500 | /* 1501 | * data4-data7 on same LOW nibble 1502 | */ 1503 | 1504 | data |= ((avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p4)) & 0xf) << 4); 1505 | 1506 | } 1507 | else if(AVRDATA_4BITHI(p4, p5, p6, p7)) 1508 | { 1509 | /* 1510 | * data4-data7 on same HIGH nibble 1511 | */ 1512 | 1513 | data |= (avrio_ReadReg(regtyp, AVRIO_PIN2AVRPORT(p4)) & 0xf0); 1514 | } 1515 | else 1516 | #endif 1517 | { 1518 | /* 1519 | * data4-data7 require BIT i/o 1520 | */ 1521 | 1522 | if(avrio_ReadBit(regtyp, p4)) data |= _BV(4); 1523 | if(avrio_ReadBit(regtyp, p5)) data |= _BV(5); 1524 | if(avrio_ReadBit(regtyp, p6)) data |= _BV(6); 1525 | if(avrio_ReadBit(regtyp, p7)) data |= _BV(7); 1526 | 1527 | } 1528 | } 1529 | return(data); 1530 | } 1531 | 1532 | /* 1533 | * Turn off all the Arduino attachment to a pin 1534 | * NOTE: currently this is VERY expensive in terms of code size for non arduino pins 1535 | * because it is a searching loop function using macros not intended for 1536 | * variables that is inlined. This is very NON-optimimum. 1537 | * 1538 | * If all pins are non arduino this will result in as much as 8k of code!!! 1539 | * 1540 | * The easiest way to solve this is with a teensy style core_pins.h 1541 | * using the defines in there, the loop goes away and is replaced 1542 | * with a macro. 1543 | */ 1544 | 1545 | #define avrio_avriomode(avrpin) \ 1546 | do \ 1547 | { \ 1548 | \ 1549 | /* \ 1550 | * If arduino pin, then use it directly \ 1551 | */ \ 1552 | if(avrpin < AVRIO_PIN(AVRIO_PORTA, 0)) \ 1553 | { \ 1554 | pinMode(avrpin, INPUT); \ 1555 | digitalWrite(avrpin, 0); \ 1556 | } \ 1557 | else \ 1558 | { \ 1559 | /* \ 1560 | * Search for arduino pin # that matches this avrpin # \ 1561 | */ \ 1562 | \ 1563 | for(int p = 0; p < (AVRIO_PIN(AVRIO_PORTA, 0)); p++) \ 1564 | { \ 1565 | if(AVRIO_PIN2AVRPIN(p) == AVRIO_PIN2AVRPIN(avrpin)) \ 1566 | { \ 1567 | pinMode(p, INPUT); \ 1568 | digitalWrite(p, 0); \ 1569 | break; \ 1570 | } \ 1571 | } \ 1572 | } \ 1573 | } while(0) 1574 | 1575 | /* 1576 | * Pin defines for all the ports/bits. 1577 | * 1578 | * These defines are for specifying a bit within a port. 1579 | * They fully define an "avrpin". And as discussed earlier they 1580 | * do not specify a type of register (PORT, PIN, DDR) they merely 1581 | * specify the bit within the "port". See the avrio primitives above 1582 | * to see how to specify the type of register (PORT, PIN, DDR) 1583 | * 1584 | * These defines allow specifyng a specific bit on a specific port. 1585 | * The general format is PIN_Pb 1586 | * Where P is a port A-Z 1587 | * and b is a bit 0-7 1588 | * 1589 | * So to specify bit 3 on port D use PIN_D3 1590 | */ 1591 | 1592 | /* 1593 | * Note: only define these if the teensy core_pins.h file has not 1594 | * already defined them. 1595 | */ 1596 | 1597 | #ifdef CORE_NUM_TOTAL_PINS 1598 | /* 1599 | * If teensy files are defining PIN_Pb defines, then there must 1600 | * also be arduino mapping macros. 1601 | */ 1602 | 1603 | #ifndef digitalPinToPortReg 1604 | #error "AVRIO: Teensy environment is missing Arduino pin mapping macros (Please update Teensy s/w)" 1605 | #endif 1606 | 1607 | #else 1608 | 1609 | 1610 | #define PIN_A0 AVRIO_PIN(AVRIO_PORTA, 0) 1611 | #define PIN_A1 AVRIO_PIN(AVRIO_PORTA, 1) 1612 | #define PIN_A2 AVRIO_PIN(AVRIO_PORTA, 2) 1613 | #define PIN_A3 AVRIO_PIN(AVRIO_PORTA, 3) 1614 | #define PIN_A4 AVRIO_PIN(AVRIO_PORTA, 4) 1615 | #define PIN_A5 AVRIO_PIN(AVRIO_PORTA, 5) 1616 | #define PIN_A6 AVRIO_PIN(AVRIO_PORTA, 6) 1617 | #define PIN_A7 AVRIO_PIN(AVRIO_PORTA, 7) 1618 | 1619 | #define PIN_B0 AVRIO_PIN(AVRIO_PORTB, 0) 1620 | #define PIN_B1 AVRIO_PIN(AVRIO_PORTB, 1) 1621 | #define PIN_B2 AVRIO_PIN(AVRIO_PORTB, 2) 1622 | #define PIN_B3 AVRIO_PIN(AVRIO_PORTB, 3) 1623 | #define PIN_B4 AVRIO_PIN(AVRIO_PORTB, 4) 1624 | #define PIN_B5 AVRIO_PIN(AVRIO_PORTB, 5) 1625 | #define PIN_B6 AVRIO_PIN(AVRIO_PORTB, 6) 1626 | #define PIN_B7 AVRIO_PIN(AVRIO_PORTB, 7) 1627 | 1628 | #define PIN_C0 AVRIO_PIN(AVRIO_PORTC, 0) 1629 | #define PIN_C1 AVRIO_PIN(AVRIO_PORTC, 1) 1630 | #define PIN_C2 AVRIO_PIN(AVRIO_PORTC, 2) 1631 | #define PIN_C3 AVRIO_PIN(AVRIO_PORTC, 3) 1632 | #define PIN_C4 AVRIO_PIN(AVRIO_PORTC, 4) 1633 | #define PIN_C5 AVRIO_PIN(AVRIO_PORTC, 5) 1634 | #define PIN_C6 AVRIO_PIN(AVRIO_PORTC, 6) 1635 | #define PIN_C7 AVRIO_PIN(AVRIO_PORTC, 7) 1636 | 1637 | #define PIN_D0 AVRIO_PIN(AVRIO_PORTD, 0) 1638 | #define PIN_D1 AVRIO_PIN(AVRIO_PORTD, 1) 1639 | #define PIN_D2 AVRIO_PIN(AVRIO_PORTD, 2) 1640 | #define PIN_D3 AVRIO_PIN(AVRIO_PORTD, 3) 1641 | #define PIN_D4 AVRIO_PIN(AVRIO_PORTD, 4) 1642 | #define PIN_D5 AVRIO_PIN(AVRIO_PORTD, 5) 1643 | #define PIN_D6 AVRIO_PIN(AVRIO_PORTD, 6) 1644 | #define PIN_D7 AVRIO_PIN(AVRIO_PORTD, 7) 1645 | 1646 | #define PIN_E0 AVRIO_PIN(AVRIO_PORTE, 0) 1647 | #define PIN_E1 AVRIO_PIN(AVRIO_PORTE, 1) 1648 | #define PIN_E2 AVRIO_PIN(AVRIO_PORTE, 2) 1649 | #define PIN_E3 AVRIO_PIN(AVRIO_PORTE, 3) 1650 | #define PIN_E4 AVRIO_PIN(AVRIO_PORTE, 4) 1651 | #define PIN_E5 AVRIO_PIN(AVRIO_PORTE, 5) 1652 | #define PIN_E6 AVRIO_PIN(AVRIO_PORTE, 6) 1653 | #define PIN_E7 AVRIO_PIN(AVRIO_PORTE, 7) 1654 | 1655 | #define PIN_F0 AVRIO_PIN(AVRIO_PORTF, 0) 1656 | #define PIN_F1 AVRIO_PIN(AVRIO_PORTF, 1) 1657 | #define PIN_F2 AVRIO_PIN(AVRIO_PORTF, 2) 1658 | #define PIN_F3 AVRIO_PIN(AVRIO_PORTF, 3) 1659 | #define PIN_F4 AVRIO_PIN(AVRIO_PORTF, 4) 1660 | #define PIN_F5 AVRIO_PIN(AVRIO_PORTF, 5) 1661 | #define PIN_F6 AVRIO_PIN(AVRIO_PORTF, 6) 1662 | #define PIN_F7 AVRIO_PIN(AVRIO_PORTF, 7) 1663 | 1664 | #define PIN_G0 AVRIO_PIN(AVRIO_PORTG, 0) 1665 | #define PIN_G1 AVRIO_PIN(AVRIO_PORTG, 1) 1666 | #define PIN_G2 AVRIO_PIN(AVRIO_PORTG, 2) 1667 | #define PIN_G3 AVRIO_PIN(AVRIO_PORTG, 3) 1668 | #define PIN_G4 AVRIO_PIN(AVRIO_PORTG, 4) 1669 | #define PIN_G5 AVRIO_PIN(AVRIO_PORTG, 5) 1670 | #define PIN_G6 AVRIO_PIN(AVRIO_PORTG, 6) 1671 | #define PIN_G7 AVRIO_PIN(AVRIO_PORTG, 7) 1672 | 1673 | #define PIN_H0 AVRIO_PIN(AVRIO_PORTH, 0) 1674 | #define PIN_H1 AVRIO_PIN(AVRIO_PORTH, 1) 1675 | #define PIN_H2 AVRIO_PIN(AVRIO_PORTH, 2) 1676 | #define PIN_H3 AVRIO_PIN(AVRIO_PORTH, 3) 1677 | #define PIN_H4 AVRIO_PIN(AVRIO_PORTH, 4) 1678 | #define PIN_H5 AVRIO_PIN(AVRIO_PORTH, 5) 1679 | #define PIN_H6 AVRIO_PIN(AVRIO_PORTH, 6) 1680 | #define PIN_H7 AVRIO_PIN(AVRIO_PORTH, 7) 1681 | 1682 | #define PIN_I0 AVRIO_PIN(AVRIO_PORTI, 0) 1683 | #define PIN_I1 AVRIO_PIN(AVRIO_PORTI, 1) 1684 | #define PIN_I2 AVRIO_PIN(AVRIO_PORTI, 2) 1685 | #define PIN_I3 AVRIO_PIN(AVRIO_PORTI, 3) 1686 | #define PIN_I4 AVRIO_PIN(AVRIO_PORTI, 4) 1687 | #define PIN_I5 AVRIO_PIN(AVRIO_PORTI, 5) 1688 | #define PIN_I6 AVRIO_PIN(AVRIO_PORTI, 6) 1689 | #define PIN_I7 AVRIO_PIN(AVRIO_PORTI, 7) 1690 | 1691 | #define PIN_J0 AVRIO_PIN(AVRIO_PORTJ, 0) 1692 | #define PIN_J1 AVRIO_PIN(AVRIO_PORTJ, 1) 1693 | #define PIN_J2 AVRIO_PIN(AVRIO_PORTJ, 2) 1694 | #define PIN_J3 AVRIO_PIN(AVRIO_PORTJ, 3) 1695 | #define PIN_J4 AVRIO_PIN(AVRIO_PORTJ, 4) 1696 | #define PIN_J5 AVRIO_PIN(AVRIO_PORTJ, 5) 1697 | #define PIN_J6 AVRIO_PIN(AVRIO_PORTJ, 6) 1698 | #define PIN_J7 AVRIO_PIN(AVRIO_PORTJ, 7) 1699 | 1700 | #define PIN_K0 AVRIO_PIN(AVRIO_PORTK, 0) 1701 | #define PIN_K1 AVRIO_PIN(AVRIO_PORTK, 1) 1702 | #define PIN_K2 AVRIO_PIN(AVRIO_PORTK, 2) 1703 | #define PIN_K3 AVRIO_PIN(AVRIO_PORTK, 3) 1704 | #define PIN_K4 AVRIO_PIN(AVRIO_PORTK, 4) 1705 | #define PIN_K5 AVRIO_PIN(AVRIO_PORTK, 5) 1706 | #define PIN_K6 AVRIO_PIN(AVRIO_PORTK, 6) 1707 | #define PIN_K7 AVRIO_PIN(AVRIO_PORTK, 7) 1708 | 1709 | #define PIN_L0 AVRIO_PIN(AVRIO_PORTL, 0) 1710 | #define PIN_L1 AVRIO_PIN(AVRIO_PORTL, 1) 1711 | #define PIN_L2 AVRIO_PIN(AVRIO_PORTL, 2) 1712 | #define PIN_L3 AVRIO_PIN(AVRIO_PORTL, 3) 1713 | #define PIN_L4 AVRIO_PIN(AVRIO_PORTL, 4) 1714 | #define PIN_L5 AVRIO_PIN(AVRIO_PORTL, 5) 1715 | #define PIN_L6 AVRIO_PIN(AVRIO_PORTL, 6) 1716 | #define PIN_L7 AVRIO_PIN(AVRIO_PORTL, 7) 1717 | 1718 | #endif // end of teensy core pin check 1719 | 1720 | #endif 1721 | 1722 | 1723 | --------------------------------------------------------------------------------