UBlox M10 Support
[openXsensor.git] / openXsensor / oXs_out_hott.cpp
blob0a6383f268411fc598fb998c370415228cf60e53
1 // File for Hott
2 #include "oXs_out_hott.h"
3 #if defined(PROTOCOL) && (PROTOCOL == HOTT)
5 #ifdef DEBUG_BLINK
6 #define DEBUG_BLINK_UPLOAD_HOTT_DATA
7 #endif
9 #ifdef DEBUG
10 // ************************* here Several parameters to help debugging
11 //#define DEBUGHOTT
12 #endif
14 extern OXS_MS5611 oXs_MS5611 ;
15 extern OXS_VOLTAGE oXs_Voltage ;
16 extern OXS_CURRENT oXs_Current ;
17 extern OXS_4525 oXs_4525 ;
18 extern OXS_SDP3X oXs_sdp3x;
21 extern unsigned long micros( void ) ;
22 extern unsigned long millis( void ) ;
23 extern void delay(unsigned long ms) ;
25 //volatile uint8_t sendStatus ;
26 volatile uint8_t flagUpdateHottBuffer ; // When a polling for oXs is received, it says that main loop must update the buffer (within the 4mes)
27 volatile uint8_t debugStatus ;
29 // Transmit buffer
30 volatile static union { // union is a easy way to access the data in several ways (name of field + index of byte)
31 volatile HOTT_GAM_MSG gamMsg ; // structured general air module
32 volatile HOTT_GPS_MSG gpsMsg ;
33 volatile uint8_t txBuffer[TXHOTTDATA_BUFFERSIZE] ;
34 } TxHottData;
38 volatile uint8_t state ; //!< Holds the state of the UART.
39 static volatile unsigned char SwUartTXData ; //!< Data to be transmitted.
40 static volatile unsigned char SwUartTXBitCount ; //!< TX bit counter.
41 static volatile uint8_t SwUartRXData ; //!< Storage for received bits.
42 static volatile uint8_t SwUartRXBitCount ; //!< RX bit counter.
43 static volatile uint8_t TxCount ;
44 static volatile uint8_t LastRx ; // last byte received (allows to check on the second byte received for polling)
45 volatile uint8_t debugUartRx ;
46 static uint8_t delayTxPendingCount ; // Used to register the number of extra delay(each 1msec) to wait in TxPending (so before replying)
47 volatile uint8_t ppmInterrupted ; // This flag is activated at the end of handling interrupt on Timer 1 Compare A if during this interrupt handling an interrupt on pin change (INT0 or INT1) occurs
48 // in this case, ppm will be wrong and has to be discarded
50 static uint8_t convertGpsFix[5] = {0x2d , 0x2d , 0x32 , 0x33 , 0x44 } ;
52 #ifdef DEBUG
53 OXS_OUT::OXS_OUT(uint8_t pinTx,HardwareSerial &print)
54 #else
55 OXS_OUT::OXS_OUT(uint8_t pinTx)
56 #endif
58 _pinTx = pinTx ;
59 #ifdef DEBUG
60 printer = &print; //operate on the address of print
61 #endif
62 } // end constructor
65 // **************** Setup the OutputLib *********************
66 void OXS_OUT::setup() {
67 // flagUpdateHottBuffer = 0 ; // does not allow to fill directly the buffer with data to transmit; in fact, filling occurs only after a polling
68 // fill the buffer with 0
69 // for ( uint8_t i = 0 ; i <= TXHOTTDATA_BUFFERSIZE ; i++ ) { // first fill the buffer with 0
70 // TxHottData.txBuffer[i] = 0 ;
71 // }
72 // fill fixed values in the buffer
73 // TxHottData.gamMsg.start_byte = 0x7c ;
74 // TxHottData.gamMsg.gam_sensor_id = 0x8d ; //GENRAL AIR MODULE = HOTT_TELEMETRY_GAM_SENSOR_ID
75 // TxHottData.gamMsg.sensor_id = 0xd0 ;
76 // TxHottData.gamMsg.stop_byte = 0x7D ;
78 //initilalise PORT
79 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input, tri-stated.
80 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is input, tri-stated.
82 // Activate pin change interupt on Tx pin
83 #if PIN_SERIALTX == 4
84 PCMSK2 |= 0x10 ; // IO4 (PD4) on Arduini mini
85 #elif PIN_SERIALTX == 2
86 PCMSK2 |= 0x04 ; // IO2 (PD2) on Arduini mini
87 #else
88 #error "This PIN is not supported"
89 #endif
90 PCIFR = (1<<PCIF2) ; // clear pending interrupt
91 initHottUart( ) ; // initialise UART
93 #ifdef DEBUGHOTT
94 printer->print(F("Hott Output Module: TX Pin="));
95 printer->println(_pinTx);
96 #endif
99 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 0) && defined(CELL_UNDERVOLTAGE_WARNING)
101 byte OXS_OUT::warning_beeps_Hott(void) { // Determine whether a warning has to be sent to the transmitter.
102 // Define the state variables for the state machine controlling the warning generation.
103 // W_IDLE is the IDLE state but that name cannot be used because IDLE is already defined in oXs_out_hott.h.
104 static enum {W_IDLE = 0, WARNING, DEADTIME} state = W_IDLE;
105 static unsigned long warning_start_time;
106 static uint8_t current_warning;
107 // In order not to flood the transmitter with warnings, we transmit our warnings only every 3 seconds.
108 // If the dead time is over, fall back into the idle state.
109 if (state == DEADTIME && millis() - warning_start_time > 3000) state = W_IDLE;
110 // State WARNING indicates that we just started to transmit a warning.
111 // Repeat it for 500ms to make sure the transmitter can receive it.
112 // After 500ms we stop transmitting the warning and disable new warnings for a while.
113 if (state == WARNING && millis() - warning_start_time > 500) {
114 state = DEADTIME;
115 current_warning = 0;
117 // In the idle state, we are ready to accept new warnings.
118 if (state == W_IDLE) {
119 if (voltageData->mVoltCellMin < CELL_UNDERVOLTAGE_WARNING) {
120 warning_start_time = millis();
121 state = WARNING;
122 current_warning = 17; /* Cell undervoltage warning */
125 return current_warning;
127 #endif
129 void OXS_OUT::sendData() {
130 #ifdef DEBUGHOTT
131 // printer->print(F("F= ")); printer->print(flagUpdateHottBuffer);
132 // printer->print(F(" S=")); printer->print(state);
133 // printer->print(F(" LR=")); printer->print(LastRx);
134 // printer->print(F(" Tc=")); printer->println(TxCount);
135 #endif
136 if ( flagUpdateHottBuffer ) { // this flag is set to true when UART get a polling of the device. Then measurement must be filled in the buffer
137 #ifdef DEBUG_BLINK_UPLOAD_HOTT_DATA
138 blinkLed(5) ; // blink every 500 ms at least
139 #endif
140 // fill the buffer with 0
141 for ( uint8_t i = 0 ; i < TXHOTTDATA_BUFFERSIZE ; i++ ) { // first fill the buffer with 0
142 TxHottData.txBuffer[i] = 0 ;
144 if ( flagUpdateHottBuffer == 0x8d ) { // this flag is set to true when UART get a polling of the GAM device. Then measurement must be filled in the buffer
145 TxHottData.gamMsg.start_byte = 0x7c ;
146 TxHottData.gamMsg.gam_sensor_id = 0x8d ; //GENRAL AIR MODULE = HOTT_TELEMETRY_GAM_SENSOR_ID
147 TxHottData.gamMsg.sensor_id = 0xd0 ;
148 TxHottData.gamMsg.stop_byte = 0x7D ;
150 // in general air module data to fill are:
151 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 1)
152 TxHottData.gamMsg.cell[0] = voltageData->mVoltCell[0] /20 ; // Volt Cell 1 (in 2 mV increments, 210 == 4.20 V)
153 #endif
154 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 2)
155 TxHottData.gamMsg.cell[1] = voltageData->mVoltCell[1] /20 ; // Volt Cell 2 (in 2 mV increments, 210 == 4.20 V)
156 #endif
157 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 3)
158 TxHottData.gamMsg.cell[2] = voltageData->mVoltCell[2] /20 ; // Volt Cell 3 (in 2 mV increments, 210 == 4.20 V)
159 #endif
160 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 4)
161 TxHottData.gamMsg.cell[3] = voltageData->mVoltCell[3] /20 ; // Volt Cell 4 (in 2 mV increments, 210 == 4.20 V)
162 #endif
163 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 5)
164 TxHottData.gamMsg.cell[4] = voltageData->mVoltCell[4] /20 ; // Volt Cell 5 (in 2 mV increments, 210 == 4.20 V)
165 #endif
166 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 6)
167 TxHottData.gamMsg.cell[5] = voltageData->mVoltCell[5] /20 ; // Volt Cell 6 (in 2 mV increments, 210 == 4.20 V)
168 #endif
169 #if defined(BATTERY_1_SOURCE) && ( (BATTERY_1_SOURCE == VOLT_1) || (BATTERY_1_SOURCE == VOLT_2) || (BATTERY_1_SOURCE == VOLT_3) || (BATTERY_1_SOURCE == VOLT_4) || (BATTERY_1_SOURCE == VOLT_5) || (BATTERY_1_SOURCE == VOLT_6) ) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
170 TxHottData.gamMsg.Battery1 = voltageData->mVolt[BATTERY_1_SOURCE - VOLT_1].value / 100; //battery 1 voltage 0.1V steps. 55 = 5.5V only pos. voltages
171 #endif
172 #if defined(BATTERY_1_SOURCE) && ( (BATTERY_1_SOURCE == ADS_VOLT_1) || (BATTERY_1_SOURCE == ADS_VOLT_2) || (BATTERY_1_SOURCE == ADS_VOLT_3) || (BATTERY_1_SOURCE == ADS_VOLT_4) ) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
173 TxHottData.gamMsg.Battery1 = ads_Conv[BATTERY_1_SOURCE - ADS_VOLT_1].value / 100; //battery 1 voltage 0.1V steps. 55 = 5.5V only pos. voltages
174 #endif
175 #if defined(BATTERY_2_SOURCE) && ( (BATTERY_2_SOURCE == VOLT_1) || (BATTERY_2_SOURCE == VOLT_2) || (BATTERY_2_SOURCE == VOLT_3) || (BATTERY_2_SOURCE == VOLT_4) || (BATTERY_2_SOURCE == VOLT_5) || (BATTERY_2_SOURCE == VOLT_6) ) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
176 TxHottData.gamMsg.Battery2 = voltageData->mVolt[BATTERY_2_SOURCE - VOLT_1].value / 100; //battery 1 voltage 0.1V steps. 55 = 5.5V only pos. voltages
177 #endif
178 #if defined(BATTERY_2_SOURCE) && ( (BATTERY_2_SOURCE == ADS_VOLT_1) || (BATTERY_2_SOURCE == ADS_VOLT_2) || (BATTERY_2_SOURCE == ADS_VOLT_3) || (BATTERY_2_SOURCE == ADS_VOLT_4) ) && defined(AN_ADS1115_IS_CONNECTED) && (AN_ADS1115_IS_CONNECTED == YES ) && defined(ADS_MEASURE)
179 TxHottData.gamMsg.Battery1 = ads_Conv[BATTERY_2_SOURCE - ADS_VOLT_1].value / 100; //battery 1 voltage 0.1V steps. 55 = 5.5V only pos. voltages
180 #endif
182 #if defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == TEST_1 )
183 TxHottData.gamMsg.temperature1 = test1.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
184 #elif defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == TEST_2 )
185 TxHottData.gamMsg.temperature1 = test2.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
186 #elif defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == TEST_3 )
187 TxHottData.gamMsg.temperature1 = test3.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
188 #elif defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == GLIDER_RATIO ) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
189 TxHottData.gamMsg.temperature1 = gliderRatio.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
190 #elif defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == SENSITIVITY ) && defined(VARIO)
191 TxHottData.gamMsg.temperature1 = oXs_MS5611.varioData.sensitivity.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
192 #elif defined(TEMPERATURE_1_SOURCE) && (TEMPERATURE_1_SOURCE == PPM ) && defined(PIN_PPM)
193 TxHottData.gamMsg.temperature1 = ppm.value + 120 ; // Hott applies an offset of 20. A value of 20 = 0°C
194 #elif defined(TEMPERATURE_1_SOURCE) && ( (TEMPERATURE_1_SOURCE == VOLT_1 ) || (TEMPERATURE_1_SOURCE == VOLT_2 ) || (TEMPERATURE_1_SOURCE == VOLT_3 ) || (TEMPERATURE_1_SOURCE == VOLT_4 ) || (TEMPERATURE_1_SOURCE == VOLT_5 ) || (TEMPERATURE_1_SOURCE == VOLT_6 ) ) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
195 TxHottData.gamMsg.temperature1 = (voltageData->mVolt[TEMPERATURE_1_SOURCE - VOLT_1].value ) / 10 + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
196 #else
197 TxHottData.gamMsg.temperature1 = 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
198 #endif
200 #if defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == TEST_1 )
201 TxHottData.gamMsg.temperature2 = test1.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
202 #elif defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == TEST_2 )
203 TxHottData.gamMsg.temperature2 = test2.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
204 #elif defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == TEST_3 )
205 TxHottData.gamMsg.temperature2 = test3.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
206 #elif defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == GLIDER_RATIO ) && defined(GLIDER_RATIO_CALCULATED_AFTER_X_SEC)
207 TxHottData.gamMsg.temperature2 = gliderRatio.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
208 #elif defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == SENSITIVITY ) && defined(VARIO)
209 TxHottData.gamMsg.temperature2 = oXs_MS5611.varioData.sensitivity.value + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
210 #elif defined(TEMPERATURE_2_SOURCE) && (TEMPERATURE_2_SOURCE == PPM ) && defined(PIN_PPM)
211 TxHottData.gamMsg.temperature2 = ppm.value + 120 ; // Hott applies an offset of 20. A value of 20 = 0°C
212 #elif defined(TEMPERATURE_2_SOURCE) && ( (TEMPERATURE_2_SOURCE == VOLT_1 ) || (TEMPERATURE_2_SOURCE == VOLT_2 ) || (TEMPERATURE_2_SOURCE == VOLT_3 ) || (TEMPERATURE_2_SOURCE == VOLT_4 ) || (TEMPERATURE_2_SOURCE == VOLT_5 ) || (TEMPERATURE_2_SOURCE == VOLT_6 ) ) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
213 TxHottData.gamMsg.temperature2 = (voltageData->mVolt[TEMPERATURE_2_SOURCE - VOLT_1].value ) /10 + 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
214 #else
215 TxHottData.gamMsg.temperature2 = 20 ; // Hott applies an offset of 20. A value of 20 = 0°C
216 #endif
218 TxHottData.gamMsg.rpm++ ;
219 if ( TxHottData.gamMsg.rpm > 1000) TxHottData.gamMsg.rpm = 1 ;
220 #ifdef MEASURE_RPM
221 TxHottData.gamMsg.rpm = RpmValue /10 ; //#22 RPM in 10 RPM steps. 300 = 3000rpm
222 #endif
223 #ifdef VARIO
224 TxHottData.gamMsg.altitude = ((varioData->relativeAlt.value ) / 100 ) + 500 ; //altitude in meters. offset of 500, 500 = 0m
225 TxHottData.gamMsg.climbrate_L = mainVspeed.value + 30000 ; //climb rate in 0.01m/s. Value of 30000 = 0.00 m/s
226 #else
227 TxHottData.gamMsg.altitude = 500 ; //altitude in meters. offset of 500, 500 = 0m
228 TxHottData.gamMsg.climbrate_L = 30000 ; //climb rate in 0.01m/s. Value of 30000 = 0.00 m/s
229 #endif
230 TxHottData.gamMsg.climbrate3s = 120 ; //#28 climb rate in m/3sec. Value of 120 = 0m/3sec
231 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
232 TxHottData.gamMsg.current = currentData->milliAmps.value /100; //current in 0.1A steps 100 == 10,0A
233 #endif
234 #if defined(MAIN_BATTERY_SOURCE) && ( (MAIN_BATTERY_SOURCE == VOLT_1) || (MAIN_BATTERY_SOURCE == VOLT_2) || (MAIN_BATTERY_SOURCE == VOLT_3) || (MAIN_BATTERY_SOURCE == VOLT_4) || (MAIN_BATTERY_SOURCE == VOLT_5) || (MAIN_BATTERY_SOURCE == VOLT_6) ) && defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
235 TxHottData.gamMsg.main_voltage = voltageData->mVolt[MAIN_BATTERY_SOURCE - VOLT_1].value / 100; //Main power voltage using 0.1V steps 100 == 10,0V] / 100
236 #endif
237 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
238 TxHottData.gamMsg.batt_cap = currentData->consumedMilliAmps.value / 10 ; // used battery capacity in 10mAh steps
239 #endif
240 #ifdef AIRSPEED
241 TxHottData.gamMsg.speed = airSpeedData->airSpeed.value ; // Km/h
242 #endif
243 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS >= 0)
244 TxHottData.gamMsg.min_cell_volt = voltageData->mVoltCellMin /20 ; // minimum cell voltage in 2mV steps. 124 = 2,48V
245 #endif
246 #if defined(NUMBEROFCELLS) && (NUMBEROFCELLS > 0) && defined(CELL_UNDERVOLTAGE_WARNING)
247 TxHottData.gamMsg.warning_beeps = warning_beeps_Hott(); // Transmitter warning message
248 #endif
250 // field of msg not implemented
251 // byte climbrate3s; //#28 climb rate in m/3sec. Value of 120 = 0m/3sec
252 // byte min_cell_volt_num; //#38 number of the cell with the lowest voltage
253 // uint16_t rpm2; //#39 LSB 2nd RPM in 10 RPM steps. 100 == 1000rpm
254 // byte general_error_number; //#41 General Error Number (Voice Error == 12) TODO: more documentation
255 // byte pressure; //#42 High pressure up to 16bar. 0,1bar scale. 20 == 2.0bar
258 #ifdef GPS_INSTALLED
259 else {
260 // here the code for GPS
261 TxHottData.gpsMsg.startByte = 0x7c ;
262 TxHottData.gpsMsg.sensorID = HOTT_TELEMETRY_GPS_SENSOR_ID ; //0x8A
263 TxHottData.gpsMsg.sensorTextID = HOTTV4_GPS_SENSOR_TEXT_ID ; // 0xA0
264 TxHottData.gpsMsg.endByte = 0x7D ;
265 uint16_t altitudeHott = 500 ; // Hott uses an offset of 500 (m)
266 if ( (GPS_fix_type == 3 ) || (GPS_fix_type == 4 ) ) {
267 // if( GPS_latAvailable ) { // test if data are available (GPS fix) ; if available, fill the buffer
268 // GPS_latAvailable = false ; // reset the flag
269 TxHottData.gpsMsg.flightDirection = GPS_ground_course / 200000 ; // convert from degre * 100000 to 1/2 degree; Flightdir./dir. 1 = 2°; 0° (North), 90° (East), 180° (South), 270° (West)
270 static uint16_t speedHott ;
271 #ifdef GPS_SPEED_3D
272 speedHott = ((uint32_t) GPS_speed_3d) * 36 /1000 ; // convert from cm/sec to km/h
273 #else
274 speedHott = ((uint32_t) GPS_speed_2d) * 36 /1000 ; // convert from cm/sec to km/h
275 #endif
276 TxHottData.gpsMsg.GPSSpeedLow = speedHott ;
277 TxHottData.gpsMsg.GPSSpeedHigh = speedHott >> 8 ;
278 uint16_t degMin ;
279 uint16_t decimalMin ;
280 TxHottData.gpsMsg.LatitudeNS = (GPS_lat < 0) ; // Byte 10: 000 = N = 48°39’0988
281 convertLonLat_Hott(GPS_lat, & degMin , & decimalMin ) ; // convert to 2 fields (one beging deg*100+min, the other being the decimal part of min with 4 decimals
282 TxHottData.gpsMsg.LatitudeMinLow = degMin ; // Byte 11: 231 = 0xE7 <= 0x12E7 = 4839
283 TxHottData.gpsMsg.LatitudeMinHigh = degMin >> 8 ; // Byte 12: 018 = 0x12 <= 0x12E7 = 4839
284 TxHottData.gpsMsg.LatitudeSecLow = decimalMin ; // Byte 13: 220 = 0xDC <= 0x03DC = 0988
285 TxHottData.gpsMsg.LatitudeSecHigh = decimalMin >> 8 ; // Byte 14: 003 = 0x03 <= 0x03DC = 0988
287 TxHottData.gpsMsg.longitudeEW = (GPS_lon < 0) ; // Byte 15: 000 = E= 9° 25’9360
288 convertLonLat_Hott(GPS_lon, &degMin , &decimalMin ) ; // convert to 2 fields (one beging deg*100+min, the other being the decimal part of min with 4 decimals
289 TxHottData.gpsMsg.longitudeMinLow = degMin ; // Byte 16: 157 = 0x9D <= 0x039D = 0925
290 TxHottData.gpsMsg.longitudeMinHigh = degMin >> 8 ; // Byte 17: 003 = 0x03 <= 0x039D = 0925
291 TxHottData.gpsMsg.longitudeSecLow = decimalMin ; // Byte 18: 144 = 0x90 <= 0x2490 = 9360
292 TxHottData.gpsMsg.longitudeSecHigh = decimalMin >> 8 ; // Byte 19: 036 = 0x24 <= 0x2490 = 9360
293 TxHottData.gpsMsg.distanceLow = GPS_distance ; // Byte 20: 027 123 = /distance low byte 6 = 6 m
294 TxHottData.gpsMsg.distanceHigh = GPS_distance >> 8 ; // Byte 21: 036 35 = /distance high byte
295 TxHottData.gpsMsg.HomeDirection = GPS_bearing / 2 ; //Byte 29: HomeDirection (direction from starting point to Model position) (1 byte) 2degree = 1
296 altitudeHott += (GPS_altitude / 1000) ; // convert from mm to m (keep the ofsset of 500 m)
299 /* not yet implemented
300 uint8_t resolutionLow; // Byte 24: 48 = Low Byte m/s resolution 0.01m 48 = 30000 = 0.00m/s (1=0.01m/s)
301 uint8_t resolutionHigh; // Byte 25: 117 = High Byte m/s resolution 0.01m
302 uint8_t unknow1; // Byte 26: 120 = 0m/3s
303 uint8_t GPSNumSat; // Byte 27: GPS.Satelites (number of satelites) (1 byte)
304 uint8_t GPSFixChar; // Byte 28: GPS.FixChar. (GPS fix character. display, if DGPS, 2D oder 3D) (1 byte)
305 uint8_t HomeDirection; // Byte 29: HomeDirection (direction from starting point to Model position) (1 byte)
306 uint8_t angleXdirection; // Byte 30: angle x-direction (1 byte)
307 uint8_t angleYdirection; // Byte 31: angle y-direction (1 byte)
308 uint8_t angleZdirection; // Byte 32: angle z-direction (1 byte)
309 uint8_t gyroXLow; // Byte 33: gyro x low byte (2 bytes)
310 uint8_t gyroXHigh; // Byte 34: gyro x high byte
311 uint8_t gyroYLow; // Byte 35: gyro y low byte (2 bytes)
312 uint8_t gyroYHigh; // Byte 36: gyro y high byte
313 uint8_t gyroZLow; // Byte 37: gyro z low byte (2 bytes)
314 uint8_t gyroZHigh; // Byte 38: gyro z high byte
315 uint8_t vibration; // Byte 39: vibration (1 bytes)
316 uint8_t Ascii4; // Byte 40: 00 ASCII Free Character [4]
317 uint8_t Ascii5; // Byte 41: 00 ASCII Free Character [5]
318 uint8_t GPS_fix; // Byte 42: 00 ASCII Free Character [6], we use it for GPS FIX
319 uint8_t version; // Byte 43: 00 version number
320 uint8_t endByte; // Byte 44: 0x7D Ende byte
321 uint8_t chksum; // Byte 45: Parity Byte
323 if (GPS_fix_type > 4 ) GPS_fix_type = 0 ;
324 TxHottData.gpsMsg.GPS_fix = TxHottData.gpsMsg.GPSFixChar = convertGpsFix[GPS_fix_type] ;
325 TxHottData.gpsMsg.GPSNumSat = GPS_numSat;
326 TxHottData.gpsMsg.altitudeLow = altitudeHott ;
327 TxHottData.gpsMsg.altitudeHigh = altitudeHott >> 8 ;
328 uint16_t varioHott = 30000 ;
329 #ifdef VARIO
330 varioHott += mainVspeed.value ; // put vario vertical speed in GPS data
331 #endif
332 TxHottData.gpsMsg.resolutionLow = varioHott ; //climb rate in 0.01m/s. Value of 30000 = 0.00 m/s
333 TxHottData.gpsMsg.resolutionHigh = varioHott >> 8;
334 TxHottData.gpsMsg.unknow1 = 120 ; // Byte 26: 120 = 0m/3s
336 } // end else => flagUpdateHottBuffer == GPS
337 #endif // end of GPS_Installed
338 // calculate the check sum on first bytes
339 TxHottData.txBuffer[TXHOTTDATA_BUFFERSIZE-1] = 0 ;
340 for(uint8_t i = 0; i < TXHOTTDATA_BUFFERSIZE-1; i++){ // one byte less because the last byte is the checksum
341 TxHottData.txBuffer[TXHOTTDATA_BUFFERSIZE-1] += TxHottData.txBuffer[i];
342 } // end for
343 flagUpdateHottBuffer = 0 ; // reset the flag to say that all data have been updated and that UART can transmit the buffer
344 #ifdef DEBUGHOTT
345 // for(uint8_t i = 0; i < TXHOTTDATA_BUFFERSIZE; i++){ // include the last byte (checksum)
346 // printer->print(TxHottData.txBuffer[i], HEX); printer->print(F(" "));
347 // } // end for
348 // printer->print(tempFlag , HEX) ;
349 // printer->println(F(" "));
350 #endif
352 } // end ( flagUpdateHottBuffer )
358 #ifdef GPS_INSTALLED
359 void convertLonLat_Hott( int32_t GPS_LatLon, uint16_t * degMin , uint16_t * decimalMin ) {
360 static uint32_t GPS_LatLonAbs ;
361 static uint16_t degre0decimals ;
362 static uint32_t minute4decimals ;
363 static uint16_t minute0decimals ;
364 GPS_LatLonAbs = ( GPS_LatLon < 0 ? - GPS_LatLon : GPS_LatLon) / 100 ; // remove 2 decimals from original value which contains degre with 7 decimals (so next calculation are smaller)
365 degre0decimals = GPS_LatLonAbs / 100000 ; // extract the degre without decimal
366 minute4decimals = ( GPS_LatLonAbs - ( ((uint32_t) degre0decimals) * 100000l ) ) * 6 ; // keep the decimal of degree and convert them in minutes (*60) and remove 1 decimal (/10) in order to keep 4 decimals
367 minute0decimals = minute4decimals / 10000 ; // extract the minutes (without decimals)
368 *degMin = degre0decimals * 100 + minute0decimals ; // put degree and minutes toegether in a special format
369 *decimalMin = minute4decimals - ( minute0decimals * 10000 ) ; // Extract the decimal part of the minutes (4 decimals)
371 #endif
372 //***************************** here code to modify for GPS
374 #ifdef GPS_INSTALLED
375 //!! shared with Aserial
376 extern uint8_t volatile gpsSendStatus ;
377 extern uint8_t volatile gpsSportDataLock ;
378 extern uint8_t volatile gpsSportData[7] ;
379 #define GPS_DATA_COUNT 5
381 void OXS_OUT::FrSkySportSensorGpsSend(void)
383 // gpsSendStatus can be TO_LOAD, LOADED, SENDING, SEND ; it is managed here and in Aserial
384 // new data is uploaded only when gpsSendStatus == SEND or TO_LOAD
385 // each GPS data is loaded in sequence but only if available (otherwise this data is skipped)
386 static uint8_t gpsDataIdx ;
387 static uint16_t gpsSportId ;
388 static uint32_t gpsSportValue ;
389 static uint32_t gpsLastLoadedMillis ;
390 #ifdef DEBUGSIMULATEGPS
391 static uint8_t gpsSimulateCount ;
392 #endif
393 // Serial.println(F("S gdps"));
395 if ((gpsSendStatus == SEND || gpsSendStatus == TO_LOAD) && (millis() - gpsLastLoadedMillis > 200 ) ){ // send only one data per 200 msec (to test if it help locking found on the Tx log)
396 gpsDataIdx++; // handle next GPS data; if not available, this field will be skipped.
397 if(gpsDataIdx >= GPS_DATA_COUNT) {
398 gpsDataIdx = 0;
400 switch(gpsDataIdx)
402 case 0: //longitude
403 if (!GPS_lonAvailable) return ;
404 GPS_lonAvailable = false ;
405 gpsSportId = GPS_LONG_LATI_FIRST_ID ;
406 #ifdef DEBUGSIMULATEGPS
407 gpsSportValue = ((( (((uint32_t)( GPS_lon < 0 ? -GPS_lon : GPS_lon)) * 6 ) / 100 ) + gpsSimulateCount++ )& 0x3FFFFFFF) | 0x80000000;
408 #else
409 gpsSportValue = (( (((uint32_t)( GPS_lon < 0 ? -GPS_lon : GPS_lon)) * 6 )/ 100 ) & 0x3FFFFFFF) | 0x80000000;
410 #endif
411 if(GPS_lon < 0) gpsSportValue |= 0x40000000;
412 break;
413 case 1: //latitude
414 if (!GPS_latAvailable) return ;
415 GPS_latAvailable = false ;
416 gpsSportId = GPS_LONG_LATI_FIRST_ID ;
417 gpsSportValue = (( (((uint32_t)( GPS_lat < 0 ? -GPS_lat : GPS_lat)) * 6 )/ 100 ) & 0x3FFFFFFF ) ;
418 if(GPS_lat < 0) gpsSportValue |= 0x40000000;
419 break;
420 case 2: // GPS_altitude
421 if (!GPS_altitudeAvailable) return ;
422 GPS_altitudeAvailable = false ;
423 gpsSportId = GPS_ALT_FIRST_ID ;
424 #ifdef DEBUGSIMULATEGPS
425 gpsSportValue = (GPS_altitude / 10) + gpsSimulateCount++; // convert mm in cm
426 #else
427 gpsSportValue = GPS_altitude / 10; // convert mm in cm
428 #endif
429 break;
430 case 3: // GPS_speed_3d // could be 2D
431 #ifdef GPS_SPEED_3D
432 if (!GPS_speed_3dAvailable) return ;
433 GPS_speed_3dAvailable = false ;
434 gpsSportId = GPS_SPEED_FIRST_ID ;
435 #ifdef GPS_SPEED_IN_KMH
436 gpsSportValue = ( ((uint32_t) GPS_speed_3d) * 36 ) ; // convert cm/s in 1/100 of km/h (factor = 3.6)
437 #else
438 gpsSportValue = ( ((uint32_t) GPS_speed_3d) * 700 ) / 36 ; // convert cm/s in 1/100 of knots (factor = 19.44)
439 #endif // end of GPS_SPEED_IN_KMH
440 break;
441 #else // use gps_Speed_2d
442 if (!GPS_speed_2dAvailable) return ;
443 GPS_speed_2dAvailable = false ;
444 gpsSportId = GPS_SPEED_FIRST_ID ;
445 #ifdef GPS_SPEED_IN_KMH
446 gpsSportValue = ( ((uint32_t) GPS_speed_2d) * 36 ) ; // convert cm/s in 1/100 of km/h (factor = 3.6)
447 #else
448 gpsSportValue = ( ((uint32_t) GPS_speed_2d) * 700 ) / 36 ; // convert cm/s in 1/1000 of knots (factor = 19.44)
449 Serial.print(F("2d Knot:"));Serial.println(gpsSportValue);
450 #endif // end of GPS_SPEED_IN_KMH
451 break;
452 #endif // enf of GPS_SPEED_3D
453 case 4: //GPS_ground_courseAvailable
454 if (!GPS_ground_courseAvailable) return ;
455 GPS_ground_courseAvailable = false ;
456 gpsSportId = GPS_COURS_FIRST_ID ;
457 gpsSportValue = GPS_ground_course / 1000; // convert from degree * 100000 to degree * 100
458 break;
459 default:
460 return ;
461 } // end case
462 gpsSportDataLock = 1 ;
463 gpsSportData[0] = 0x10 ;
464 gpsSportData[1] = gpsSportId ; // low byte
465 gpsSportData[2] = gpsSportId >> 8 ; // hight byte
466 gpsSportData[3] = gpsSportValue ;
467 gpsSportData[4] = gpsSportValue >> 8 ;
468 gpsSportData[5] = gpsSportValue >> 16 ;
469 gpsSportData[6] = gpsSportValue >> 24 ;
470 gpsSportDataLock = 0 ;
471 #ifdef DEBUGSENDGPS
472 Serial.print(F("ID: "));
473 Serial.println(gpsSportId , HEX);
474 #endif
476 gpsSendStatus = LOADED ; // from here data can be sent by the interrupt in Aserial
477 } // end test on gpsSendStatus == SEND or TOLOAD
478 } // end function
480 #endif // of of GPS_INSTALLED
487 void convert_to_degrees_minutes_seconds(float val, int *deg_sec, int *degMin){
488 int16_t deg = (int)val;
489 double sec = (val - deg);
490 int8_t min = (int) (sec * 60);
492 *deg_sec = abs((int) (((sec * 60) - min) * 10000.0f));
493 *degMin = abs((int)(deg * 100 + min));
496 /*tinygps FORMAT dd.ddddd
497 void convert_to_degrees_minutes_seconds(float val, int *deg_sec, int *degMin){
498 int16_t deg = (int)val; //extract degrees
499 float sec = (val - deg);
500 int8_t min = (int) (sec * 60);//extract decimal deg
502 *deg_sec = abs((int) (((sec * 60) - min) * 100000.0f));
503 *degMin = abs((int)(deg * 100 + min));
506 static void hottV4GPSUpdate() {
507 //number of Satelites
508 HoTTV4GPSModule.GPSNumSat=MultiHoTTModule.GPS_numSat;
509 if (MultiHoTTModule.GPS_fix > 0) {
510 // GPS fix
511 HoTTV4GPSModule.GPS_fix = 0x33; // Dgps: '0x44' 2D = '0x32' 3D = '0x33' nofix = '0x2d'
513 int16_t deg_sec;
514 int16_t degMin;
516 //latitude
517 convert_to_degrees_minutes_seconds(MultiHoTTModule.GPS_latitude, &deg_sec, &degMin);
518 HoTTV4GPSModule.LatitudeNS=(MultiHoTTModule.GPS_latitude<0);
519 HoTTV4GPSModule.LatitudeMinLow = degMin;
520 HoTTV4GPSModule.LatitudeMinHigh = degMin >> 8;
521 HoTTV4GPSModule.LatitudeSecLow = deg_sec;
522 HoTTV4GPSModule.LatitudeSecHigh = deg_sec >> 8;
525 //longitude
526 convert_to_degrees_minutes_seconds(MultiHoTTModule.GPS_longitude, &deg_sec, &degMin);
527 HoTTV4GPSModule.longitudeEW=(MultiHoTTModule.GPS_longitude<0);
528 HoTTV4GPSModule.longitudeMinLow = degMin;
529 HoTTV4GPSModule.longitudeMinHigh = degMin >> 8;
530 HoTTV4GPSModule.longitudeSecLow = deg_sec;
531 HoTTV4GPSModule.longitudeSecHigh = deg_sec >> 8;
534 // GPS Speed in km/h
535 uint16_t speed = MultiHoTTModule.GPS_speed; // in km/h
536 HoTTV4GPSModule.GPSSpeedLow = speed & 0x00FF;
537 HoTTV4GPSModule.GPSSpeedHigh = speed >> 8;
538 // Distance to home
539 HoTTV4GPSModule.distanceLow = MultiHoTTModule.GPS_distanceToHome & 0x00FF;
540 HoTTV4GPSModule.distanceHigh = MultiHoTTModule.GPS_distanceToHome >> 8;
541 // Altitude
542 HoTTV4GPSModule.altitudeLow = MultiHoTTModule.GPS_altitude & 0x00FF;
543 HoTTV4GPSModule.altitudeHigh = MultiHoTTModule.GPS_altitude >> 8;
544 // Home Direction
545 HoTTV4GPSModule.HomeDirection = MultiHoTTModule.GPS_directionToHome;
546 // Flightdirection
547 HoTTV4GPSModule.flightDirection = MultiHoTTModule.GPS_flightDirection;
549 //VARIO not implemented yet, should be a BMP085
550 //m/s
551 HoTTV4GPSModule.resolutionLow = MultiHoTTModule.GPS_distanceToHome & 0x00FF;
552 HoTTV4GPSModule.resolutionHigh = MultiHoTTModule.GPS_distanceToHome >> 8;
553 //m/3s
554 HoTTV4GPSModule.unknow1 = MultiHoTTModule.GPS_flightDirection;
556 HoTTV4GPSModule.alarmTone = MultiHoTTModule.GPS_alarmTone;
558 } else {
559 HoTTV4GPSModule.GPS_fix = 0x2d; // Displays a ' ' to show nothing or clear the old value
565 // Sends HoTTv4 capable GPS telemetry frame.
566 static void hottV4SendGPS() {
567 // Minimum data set for EAM
568 HoTTV4GPSModule.startByte = 0x7C;
569 HoTTV4GPSModule.sensorID = HOTTV4_GPS_SENSOR_ID;
570 HoTTV4GPSModule.sensorTextID = HOTTV4_GPS_SENSOR_TEXT_ID;
571 HoTTV4GPSModule.endByte = 0x7D;
574 hottV4GPSUpdate();
576 if (is_set_home == 0)
578 HoTTV4GPSModule.alarmTone = 0x08; //alarm tone if no fix
579 toggle_LED(); //Let the led blink
580 }else
582 HoTTV4GPSModule.alarmTone = 0x0;
585 // Clear output buffer
586 memset(&outBuffer, 0, sizeof(outBuffer));
588 // Copy GPS data to output buffer
589 memcpy(&outBuffer, &HoTTV4GPSModule, kHoTTv4BinaryPacketSize);
591 // Send data from output buffer
592 hottV4SendData(outBuffer, kHoTTv4BinaryPacketSize);
596 // **************************** End of code for GPS (still to modify
601 //---------------------------------- Here the code to handle the UART
602 #ifdef DEBUG
603 //#define DEBUGSETNEWDATA
604 //#define DEBUGASERIAL
605 #endif
607 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
610 ISR(TIMER1_COMPA_vect)
612 switch (state)
614 case TRANSMIT : // startbit has been sent, it is time to output now 8 bits and 1 stop bit
615 #if DEBUGASERIAL
616 PORTC |= 1 ;
617 #endif
618 if( SwUartTXBitCount < 8 ) { // If not 8 bits have been sent
619 if( SwUartTXData & 0x01 ) { // If the LSB of the TX buffer is 1:
620 SET_TX_PIN_MB() ;
621 } else { // Otherwise:
622 CLEAR_TX_PIN_MB() ; // Send a logic 0 on the TX_PIN
624 SwUartTXData = SwUartTXData >> 1 ; // Bitshift the TX buffer and
625 SwUartTXBitCount += 1 ; // increment TX bit counter.
626 } else { //Send stop bit.
627 SET_TX_PIN_MB() ; // Output a logic 1. (in high impedance) = put stop bit
628 state = TRANSMIT_STOP_BIT;
629 OCR1A += DELAY_2000; // Normally Add 2 msec to the stop bit (required by Hott protocol)
631 OCR1A += TICKS2WAITONEHOTT ; // Count one period into the future.
632 #if DEBUGASERIAL
633 PORTC &= ~1 ;
634 #endif
635 break ;
637 case TRANSMIT_STOP_BIT: //************************************* handling after the stop bit has been sent
638 if ( ++TxCount < TXHOTTDATA_BUFFERSIZE ) {
639 SwUartTXData = TxHottData.txBuffer[TxCount] ;
640 CLEAR_TX_PIN_MB(); // Send a logic 0 on the TX_PIN as start bit
641 OCR1A = TCNT1 + TICKS2WAITONEHOTT - INTERRUPT_BETWEEN_TRANSMIT ; // Count one period into the future.
642 SwUartTXBitCount = 0 ;
643 state = TRANSMIT ;
644 } else { // all bytes have already been sent
645 state = WAITING ;
646 OCR1A += DELAY_2000; // 2mS gap before listening
647 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input
648 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is tri-stated.
650 break ;
652 case RECEIVE : // Start bit has been received and we will read bits of data receiving, LSB first.
653 OCR1A += TICKS2WAITONEHOTT ; // Count one period after the falling edge is trigged.
654 uint8_t data ; // Use a temporary local storage (it save some bytes (and perhaps time)
655 data = SwUartRXBitCount ;
656 if( data < 8 ) { //If 8 bits are not yet read
657 SwUartRXBitCount = data + 1 ;
658 data = SwUartRXData ;
659 data >>= 1 ; // Shift due to receiving LSB first.
660 if( !(GET_RX_PIN( ) == 0 )) data |= 0x80 ; // If a logical 1 is read, let the data mirror this.
661 SwUartRXData = data ;
662 } else { //Done receiving = 8 bits are in SwUartRXData
663 if ( ( LastRx == HOTT_BINARY_MODE_REQUEST_ID ) && ( ( SwUartRXData == HOTT_TELEMETRY_GAM_SENSOR_ID) // if the previous byte identifies a polling for a reply in binary format and current is oXs sensor ID
664 #ifdef GPS_INSTALLED
665 || ( SwUartRXData == HOTT_TELEMETRY_GPS_SENSOR_ID )
666 #endif
667 ) ) { // the sensor has to reply (if it has data; here we assume it has always data and the data will be in the Hott buffer)
668 flagUpdateHottBuffer = SwUartRXData ; // flag to say to send function that the buffer must be filled. It is expected that send function is called fast enough (so main loop may not be blocked)
669 state = TxPENDING ;
670 OCR1A += ( DELAY_4000 - TICKS2WAITONEHOTT) ; // 4ms gap before sending; normally Hott protocols says to wait 5 msec but this is too much for timer1
671 delayTxPendingCount = 1 ; // ask for 1 more delay of 1ms in order to reach the total of 5msec
672 } else { // Previous code is not equal to HOTT_BINARY_MODE_REQUEST_ID , enter to iddle mode (so we will accept to read another byte)
673 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
674 state = IDLE ; // Go back to idle.
675 PCIFR = ( 1<<PCIF2 ) ; // clear pending interrupt
676 PCICR |= ( 1<<PCIE2 ) ; // pin change interrupt enabled
678 LastRx = SwUartRXData ; // save the byte being received; so next time a byte is received, comparison is possible.
679 } // End receiving 1 byte (8 bits) (and 1 bit)
680 break ;
682 case TxPENDING : //End of delay before sending data has occurs
683 if ( delayTxPendingCount ) { // if additional delay is requested, perform it
684 delayTxPendingCount--;
685 OCR1A += DELAY_1000 ;
686 } else {
687 if ( flagUpdateHottBuffer ) { // it is expected that the main loop will update the buffer and set this flag to true within the delay
688 OCR1A += DELAY_1000 ; // if it is not yet done, stay TxPENDING for 1 msec more
689 // state = WAITING ;
690 } else {
691 CLEAR_TX_PIN_MB() ; // Send a start bit (logic 0 on the TX_PIN).
692 OCR1A = TCNT1 + TICKS2WAITONEHOTT - INTERRUPT_ENTRY_TRANSMIT ; // Count one period into the future (less due to time to enter ISR)
693 SwUartTXBitCount = 0 ;
694 SwUartTXData = TxHottData.txBuffer[0] ;
695 TxCount = 0 ;
696 state = TRANSMIT ;
699 break ;
701 case WAITING : // At the end of wait time, stop timer interrupt but allow pin change interrupt in order to allow to detect incoming data
702 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
703 state = IDLE ; // Go back to idle.
704 CLEAR_PIN_CHANGE_INTERRUPT() ; // clear pending pin change interrupt
705 ENABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt enabled
706 break ;
708 // Unknown state.
709 default:
710 state = IDLE; // Error, should not occur. Going to a safe state.
711 } // End CASE
712 //#ifdef PPM_INTERRUPT
713 // if ( EIFR & PPM_INT_BIT) ppmInterrupted = 1 ;
714 //#endif
716 } // End of ISR
719 // *********************************** initialise UART for Hott protocol *********************************************
720 // This function will set up pins to transmit and receive on. Control of Timer1 and pin change interrupt 0.
721 void initHottUart( ) //*************** initialise UART for Multiplex
723 //PORT
724 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input.
725 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is tri-stated.
727 // External interrupt
729 #if PIN_SERIALTX == 4
730 PCMSK2 |= 0x10 ; // IO4 (PD4) on Arduini mini
731 #elif PIN_SERIALTX == 2
732 PCMSK2 |= 0x04 ; // IO2 (PD2) on Arduini mini
733 #else
734 #error "This PIN is not supported"
735 #endif
736 CLEAR_PIN_CHANGE_INTERRUPT() ;
737 ENABLE_PIN_CHANGE_INTERRUPT() ;
738 state = IDLE ; // Internal State Variable
740 #if DEBUGASERIAL
741 DDRC = 0x01 ; // PC0 as o/p debug = pin A0 !!!!
742 PORTC = 0 ;
743 #endif
747 // ! \brief External interrupt service routine. ********************
748 // Interrupt on Pin Change to detect change on level on Hott signal (= could be a start bit)
750 // The falling edge in the beginning of the start
751 // bit will trig this interrupt. The state will
752 // be changed to RECEIVE, and the timer interrupt
753 // will be set to trig one and a half bit period
754 // from the falling edge. At that instant the
755 // code should sample the first data bit.
757 // note initHottUart( void ) must be called in advance.
759 // This is the pin change interrupt for port D
760 // This assumes it is the only pin change interrupt
761 // on this port
763 ISR(PCINT2_vect) // There is a start bit.
765 if (!( TRXPIN & ( 1 << PIN_SERIALTX ) )) { // Pin is low = start bit
766 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
767 state = RECEIVE ; // Change state
768 DISABLE_TIMER_INTERRUPT() ; // Disable timer to change its registers.
769 OCR1A = TCNT1 + TICKS2WAITONE_HALFHOTT - INTERRUPT_EXEC_CYCL - INTERRUPT_EARLY_BIAS ; // Count one and a half period into the future.
770 #if DEBUGASERIAL
771 PORTC |= 1 ;
772 #endif
773 SwUartRXBitCount = 0 ; // Clear received bit counter.
774 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
775 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
777 //#ifdef PPM_INTERRUPT
778 // if ( EIFR & PPM_INT_BIT) ppmInterrupted = 1 ;
779 //#endif
781 } // end ISR pin change
784 // -------------------------End of HOTT protocol--------------------------------------------------------------------------------------
786 #endif // END of HOTT