Update oXs_out_frsky.cpp
[openXsensor.git] / openXsensor / oXs_out_multiplex.cpp
blobe244a64db2b8a124bc44e1040545807249e9a8f9
1 // File for Multiplex
2 #include "oXs_out_multiplex.h"
3 #if defined(PROTOCOL) && (PROTOCOL == MULTIPLEX)
5 #ifdef DEBUG
6 // ************************* Several parameters to help debugging
7 //#define DEBUGSETNEWDATA
8 //#define DEBUGFORMATONEVALUE
9 #endif
10 //#define DEBUG_MULTIPLEX_WITHOUT_RX // this allows to let oXs generates dummy data when there is no Rx to give the polling on the bus. In this case, oXs does not look at the pooling to send data
11 //#define DEBUG_FORCE_VSPEED_TO 123 // this is used to force oXs to send a fixed dummy value for Vspeed in order to test if an issue result of bmp180 or from Multiplex protocol.
13 extern unsigned long micros( void ) ;
14 extern unsigned long millis( void ) ;
15 extern void delay(unsigned long ms) ;
17 struct t_mbAllData multiplexData ;
18 volatile uint8_t sendStatus ;
19 int fieldContainsData[][7] = { SETUP_MULTIPLEX_DATA_TO_SEND } ; // contains the set up of field to be transmitted, the first field contains the Multiplex adress to be used for this measurement
20 int numberOfFields = sizeof(fieldContainsData) / sizeof(fieldContainsData[0]) ;
21 uint8_t multiplexUnit[] = { MULTIPLEX_UNITS } ; // contains the unit code (4 bits) for each OXS measurement
23 #ifdef DEBUG
24 OXS_OUT::OXS_OUT(uint8_t pinTx,HardwareSerial &print)
25 #else
26 OXS_OUT::OXS_OUT(uint8_t pinTx)
27 #endif
29 _pinTx = pinTx ;
30 #ifdef DEBUG
31 printer = &print; //operate on the address of print
32 #endif
33 } // end constructor
36 // **************** Setup the OutputLib *********************
37 void OXS_OUT::setup() {
39 //initilalise PORT
40 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input, tri-stated.
41 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is input, tri-stated.
43 // Activate pin change interupt on Tx pin
44 #if PIN_SERIALTX == 4
45 PCMSK2 |= 0x10 ; // IO4 (PD4) on Arduini mini
46 #elif PIN_SERIALTX == 2
47 PCMSK2 |= 0x04 ; // IO2 (PD2) on Arduini mini
48 #else
49 #error "This PIN is not supported"
50 #endif
52 PCIFR = (1<<PCIF2) ; // clear pending interrupt
54 //initMultiplexUart( &sportData ) ;
55 initMultiplexUart( &multiplexData ) ;
57 #ifdef DEBUG
58 printer->print(F("Multiplex Output Module: TX Pin="));
59 printer->println(_pinTx);
60 printer->print(F(" milli="));
61 printer->println(millis());
62 printer->println(F("Multiplex Output Module: Setup!"));
63 printer->print(F("Number of fields to send = "));
64 printer->println(numberOfFields);
65 for (int rowNr = 0 ; rowNr < numberOfFields ; rowNr++) {
66 printer->print(fieldContainsData[rowNr][0],HEX); printer->print(F(" , "));
67 printer->print(fieldContainsData[rowNr][1]); printer->print(F(" , "));
68 printer->print(fieldContainsData[rowNr][2]); printer->print(F(" , "));
69 printer->print(fieldContainsData[rowNr][3]); printer->print(F(" , "));
70 printer->println(fieldContainsData[rowNr][4]);
72 #endif
73 for ( int mbIndex = 0 ; mbIndex <= MB_MAX_ADRESS ; mbIndex++ ) {
74 multiplexData.mbData[mbIndex].response[0] = mbIndex ;
75 multiplexData.mbData[mbIndex].active = NOT_ACTIVE ;
77 for ( int mbIndex = 0 ; mbIndex < numberOfFields ; mbIndex++ ) {
78 multiplexData.mbData[fieldContainsData[mbIndex][0]].response[0] = ( fieldContainsData[mbIndex][0] << 4) | ( multiplexUnit[ fieldContainsData[mbIndex][1] ] );
79 multiplexData.mbData[fieldContainsData[mbIndex][0]].response[1] = (uint8_t) MB_NOVALUE ; // low byte
80 multiplexData.mbData[fieldContainsData[mbIndex][0]].response[2] = MB_NOVALUE >> 8 ; // hight byte
81 multiplexData.mbData[fieldContainsData[mbIndex][0]].active = AVAILABLE ;
84 // for debug purpose only
85 multiplexData.mbData[15].response[0] = 0xF0 ;
86 multiplexData.mbData[15].response[1] = 0x0F ;
87 multiplexData.mbData[15].response[2] = 0xAA ;
88 #ifdef DEBUG
89 for ( int mbIndex = 0 ; mbIndex <= MB_MAX_ADRESS ; mbIndex++ ) {
90 Serial.print("id=");
91 Serial.print( mbIndex);
92 Serial.print(" Act=");
93 Serial.print( multiplexData.mbData[mbIndex].active, HEX );
94 Serial.print(" r0=");
95 Serial.print( multiplexData.mbData[mbIndex].response[0], HEX);
96 Serial.print(" r1=");
97 Serial.print( multiplexData.mbData[mbIndex].response[1], HEX);
98 Serial.print(" r2=");
99 Serial.println( multiplexData.mbData[mbIndex].response[2], HEX);
101 #endif
108 void OXS_OUT::sendData()
110 for ( uint8_t mbIndex = 0 ; mbIndex < numberOfFields ; mbIndex++ ) {
111 formatOneValue( mbIndex ) ;
115 //*************************************
116 // Format the sensor data into an array containing the 3 bytes to sent
117 // process occurs only if measurement has been flagged as available by the sensor
118 // return 0 if data has been processed; return the internal code of the measurement otherwise
119 //************************************
120 uint8_t OXS_OUT::formatOneValue( uint8_t currentFieldToSend) {
121 static int32_t valueTemp ;
122 static uint8_t alarm ;
123 // int fieldID ;
124 // fieldID = 0 ;
125 valueTemp = 0 ;
127 #ifdef GPS_INSTALLED
128 uint8_t GPS_no_fix = ( (GPS_fix_type != 3 ) && (GPS_fix_type != 4 ) ) ; // this flag is true when there is no fix
129 #endif
131 switch ( fieldContainsData[currentFieldToSend][1] ) {
132 #ifdef VARIO
133 case ALTIMETER :
134 if ( ! varioData->absoluteAlt.available ) return 0 ;
135 valueTemp = (varioData->absoluteAlt.value ) / 100 ;
136 varioData->absoluteAlt.available = false ;
137 #ifdef DEBUGFORMATONEVALUE
138 Serial.print("At ");
139 Serial.print( millis());
140 Serial.print("id=");
141 Serial.print( currentFieldToSend );
142 Serial.println("Alt available ");
143 #endif
144 break ;
145 case VERTICAL_SPEED :
146 if ( ! mainVspeed.available ) return 0;
147 valueTemp = mainVspeed.value / 10 ;
148 mainVspeed.available = false ;
149 #ifdef DEBUG_FORCE_VSPEED_TO
150 valueTemp = DEBUG_FORCE_VSPEED_TO ;
151 #endif
152 break ;
153 case SENSITIVITY :
154 if ( !varioData->sensitivity.available ) return 0;
155 valueTemp = varioData->sensitivity.value ;
156 varioData->sensitivity.available = false ;
157 break ;
158 // case ALT_OVER_10_SEC :
159 // if ( ! varioData->vSpeed10SecAvailable ) return 0;
160 // valueTemp = varioData->vSpeed10Sec / 100 ; // todo : adjust decimals
161 // varioData->vSpeed10SecAvailable = false ;
162 // break ;
163 case REL_ALTIMETER :
164 if ( ! varioData->relativeAlt.available ) return 0 ;
165 valueTemp = (varioData->relativeAlt.value ) / 100 ;
166 varioData->relativeAlt.available = false ;
167 break ;
168 case ALTIMETER_MAX :
169 if ( ! varioData->relativeAltMaxAvailable ) return 0 ;
170 valueTemp = (varioData->relativeAltMax ) / 100 ;
171 varioData->relativeAltMaxAvailable = false ;
172 break ;
174 #endif // End vario
177 #ifdef VARIO2
178 case ALTIMETER_2 :
179 if ( ! varioData_2->absoluteAltAvailable ) return 0;
180 valueTemp = varioData_2->absoluteAlt / 100 ;
181 varioData_2->absoluteAltAvailable = false ;
182 break ;
183 case VERTICAL_SPEED_2 :
184 if ( ! varioData_2->climbRateAvailable ) return 0;
185 valueTemp = varioData_2->climbRate / 10 ;
186 varioData_2->climbRateAvailable = false ;
187 break ;
188 case SENSITIVITY_2 :
189 if ( ! varioData_2->sensitivityAvailable ) return 0;
190 valueTemp = varioData_2->sensitivity ;
191 varioData_2->sensitivityAvailable = false ;
192 break ;
193 case ALT_OVER_10_SEC_2 :
194 if ( ! varioData_2->vSpeed10SecAvailable ) return 0;
195 valueTemp = varioData_2->vSpeed10Sec / 100 ; // todo : adjust decimals
196 varioData_2->vSpeed10SecAvailable = false ;
197 break ;
198 case REL_ALTIMETER_2 :
199 if ( ! varioData_2->relativeAltAvailable ) return 0 ;
200 valueTemp = (varioData_2->relativeAlt ) / 100 ;
201 varioData_2->relativeAltAvailable = false ;
202 break ;
203 #endif // End vario2
206 #if defined (VARIO ) && defined (VARIO2)
207 case VERTICAL_SPEED_A :
208 if ( ! averageVSpeedAvailable ) return 0;
209 valueTemp = averageVSpeed / 10 ;
210 averageVSpeedAvailable = false ;
211 break ;
212 #endif
214 #if defined (VARIO ) && ( defined (VARIO2) || defined( AIRSPEED) || defined( USE_6050) ) && defined (VARIO_PRIMARY ) && defined (VARIO_SECONDARY ) && defined (PIN_PPM)
215 case PPM_VSPEED :
216 if ( ! switchVSpeedAvailable ) return 0;
217 valueTemp = switchVSpeed / 10 ;
218 switchVSpeedAvailable = false ;
219 break ;
220 #endif
222 #ifdef AIRSPEED_IS_USED
223 case AIR_SPEED :
224 if ( ! airSpeedData->airSpeed.available ) return 0;
225 valueTemp = airSpeedData->airSpeed.value * 1.852; // convert from 1/10 of knots to 1/10 of Km/h
226 airSpeedData->airSpeed.available = false ;
227 break ;
228 // case PRANDTL_COMPENSATION :
229 // if ( ! airSpeedData->compensationAvailable ) return 0;
230 // valueTemp = airSpeedData->compensation / 10 ;
231 // airSpeedData->compensationAvailable = false ;
232 // break ;
233 #endif // End airpseed
235 //#if defined (VARIO) && defined ( AIRSPEED)
236 // case PRANDTL_DTE :
237 // if ( ! compensatedClimbRateAvailable ) return 0;
238 // valueTemp = compensatedClimbRate / 10 ;
239 // compensatedClimbRateAvailable = false ;
240 // break ;
241 //#endif // End defined (VARIO) && defined ( AIRSPEED)
243 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES)
244 case VOLT_1 :
245 if (! voltageData->mVolt[0].available ) return 0;
246 valueTemp = voltageData->mVolt[0].value / 100;
247 voltageData->mVolt[0].available = false ;
248 break ;
249 case VOLT_2 :
250 if ( ! voltageData->mVolt[1].available ) return 0;
251 valueTemp = voltageData->mVolt[1].value / 100 ;
252 voltageData->mVolt[1].available = false ;
253 break ;
254 case VOLT_3 :
255 if ( ! voltageData->mVolt[2].available ) return 0;
256 valueTemp = voltageData->mVolt[2].value / 100 ;
257 voltageData->mVolt[2].available = false ;
258 break ;
259 case VOLT_4 :
260 if ( ! voltageData->mVolt[3].available ) return 0;
261 valueTemp = voltageData->mVolt[3].value / 100 ;
262 voltageData->mVolt[3].available = false ;
263 break ;
264 case VOLT_5 :
265 if ( ! voltageData->mVolt[4].available ) return 0;
266 valueTemp = voltageData->mVolt[4].value / 100 ;
267 voltageData->mVolt[4].available = false ;
268 break ;
269 case VOLT_6 :
270 if ( ! voltageData->mVolt[5].available ) return 0;
271 valueTemp = voltageData->mVolt[5].value / 100 ;
272 voltageData->mVolt[5].available = false ;
273 break ;
274 #endif
276 #if defined(ARDUINO_MEASURES_A_CURRENT) && (ARDUINO_MEASURES_A_CURRENT == YES)
277 case CURRENTMA :
278 if ( ! currentData->milliAmps.available ) return 0;
279 valueTemp = currentData->milliAmps.value /100;
280 currentData->milliAmps.available = false ;
281 break ;
282 case MILLIAH :
283 if ( ! currentData->consumedMilliAmps.available ) return 0;
284 valueTemp = currentData->consumedMilliAmps.value ;
285 currentData->consumedMilliAmps.available = false ;
286 break ;
287 #endif
289 #if defined(ARDUINO_MEASURES_VOLTAGES) && (ARDUINO_MEASURES_VOLTAGES == YES) && (NUMBEROFCELLS > 0) // This part has still to be adapted for Multiplex !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
290 case CELL_1 :
291 if ( ! voltageData->mVoltCell_Available[0] ) return 0;
292 valueTemp = voltageData->mVoltCell[0] /100 ;
293 voltageData->mVoltCell_Available[0] = false ;
294 break ;
295 case CELL_2 :
296 if ( ! voltageData->mVoltCell_Available[1] ) return 0;
297 valueTemp = voltageData->mVoltCell[1] / 100 ;
298 voltageData->mVoltCell_Available[1] = false ;
299 break ;
300 case CELL_3 :
301 if ( ! voltageData->mVoltCell_Available[2] ) return 0;
302 valueTemp = voltageData->mVoltCell[2] / 100 ;
303 voltageData->mVoltCell_Available[2] = false ;
304 break ;
305 case CELL_4 :
306 if ( ! voltageData->mVoltCell_Available[3] ) return 0;
307 valueTemp = voltageData->mVoltCell[3] / 100 ;
308 voltageData->mVoltCell_Available[3] = false ;
309 break ;
310 case CELL_5 :
311 if ( ! voltageData->mVoltCell_Available[4] ) return 0;
312 valueTemp = voltageData->mVoltCell[4] / 100 ;
313 voltageData->mVoltCell_Available[4] = false ;
314 break ;
315 case CELL_6 :
316 if ( ! voltageData->mVoltCell_Available[5] ) return 0;
317 valueTemp = voltageData->mVoltCell[5] / 100 ;
318 voltageData->mVoltCell_Available[5] = false ;
319 break ;
320 case CELL_MIN :
321 if ( ! voltageData->mVoltCellMin_Available ) return 0;
322 valueTemp = voltageData->mVoltCellMin / 100 ;
323 voltageData->mVoltCellMin_Available = false ;
324 break ;
325 case CELL_TOT :
326 if ( ! voltageData->mVoltCellTot_Available ) return 0;
327 valueTemp = voltageData->mVoltCellTot / 100 ;
328 voltageData->mVoltCellTot_Available = false ;
329 break ;
331 #endif // NUMBEROFCELLS > 0
333 #ifdef PIN_PPM
334 case PPM :
335 if ( ! ppm.available ) return 0;
336 valueTemp = ppm.value ;
337 ppm.available = false ;
338 break ;
339 #endif
342 #ifdef MEASURE_RPM
343 case RPM :
344 if ( ! sport_rpm.available ) return 0;
345 #if defined (PULSES_PER_ROTATION)
346 valueTemp = sport_rpm.value * 60.0 / PULSES_PER_ROTATION ;
347 #else // if PULSES_PER_ROTATION is not defined, we assume 1
348 valueTemp = sport_rpm.value * 60 ;
349 #endif
350 sport_rpm.available = false ;
351 break ;
352 #endif
353 case TEST_1 :
354 if ( ! test1.available ) return 0;
355 valueTemp = test1.value ;
356 test1.available = false ;
357 break ;
358 case TEST_2 :
359 if ( ! test2.available ) return 0;
360 valueTemp = test2.value ;
361 test2.available = false ;
362 break ;
363 case TEST_3 :
364 if ( ! test3.available ) return 0;
365 valueTemp = test3.value ;
366 test3.available = false ;
367 break ;
369 #ifdef GPS_INSTALLED
370 case GPS_COURSE :
371 if (GPS_no_fix ) return 0 ;
372 valueTemp = GPS_ground_course / 10000 ; // convert from degre * 100000 to 1/10 of degree
373 break ;
374 case GPS_SPEED :
375 if (GPS_no_fix ) return 0 ;
376 #ifdef GPS_SPEED_3D
377 valueTemp = ((uint32_t) GPS_speed_3d) * 36 /100 ; // convert from cm/sec to 1/10 of km/h
378 #else
379 valueTemp = ((uint32_t) GPS_speed_2d) * 36 /100 ; // convert from cm/sec to 1/10 of km/h
380 #endif
381 break ;
382 case GPS_ALTITUDE :
383 if (GPS_no_fix ) return 0 ;
384 valueTemp = GPS_altitude / 1000 ; // convert from mm to m
385 break ;
386 case GPS_DISTANCE :
387 if (GPS_no_fix ) return 0 ;
388 valueTemp = GPS_distance ; // keep in m
389 break ;
390 case GPS_BEARING :
391 if (GPS_no_fix ) return 0 ;
392 valueTemp = GPS_bearing * 10 ; // convert from degree to 1/10 of degree
393 break ;
394 #endif // end GPS_INSTALLED
395 } // end Switch
396 // if ( (fieldContainsData[currentFieldToSend][0] != 0) ) { ; // to be adapted in a condition that protect modification of data array while data are transfered to TX buffer array
397 // }
398 valueTemp = (valueTemp * fieldContainsData[currentFieldToSend][2] / fieldContainsData[currentFieldToSend][3]) + fieldContainsData[currentFieldToSend][4] ;
399 alarm = (( valueTemp <= fieldContainsData[currentFieldToSend][5] ) || ( valueTemp >= fieldContainsData[currentFieldToSend][6]) ) ? 1 : 0;
400 setMultiplexNewData( fieldContainsData[currentFieldToSend][0] , valueTemp , alarm ) ;
401 return fieldContainsData[currentFieldToSend][1] ;
402 } // End function
405 void OXS_OUT::setMultiplexNewData( uint16_t id, int32_t value , uint8_t alarm)
407 #ifdef DEBUGSETNEWDATA
408 int32_t valueOrig = value ;
409 #endif
410 multiplexData.mbData[id].active = LOCKED ;
411 value = value << 1 ;
412 value += alarm ;
413 multiplexData.mbData[id].response[1] = value ;
414 multiplexData.mbData[id].response[2] = value >> 8 ;
415 multiplexData.mbData[id].active = AVAILABLE ;
416 #ifdef DEBUGSETNEWDATA
417 Serial.print("set new data at ");
418 Serial.print( millis());
419 Serial.print(" for id=");
420 Serial.print( id );
421 Serial.print(" ");
422 Serial.print( multiplexData.mbData[id].response[0] , HEX );
423 Serial.print(" ");
424 Serial.print( multiplexData.mbData[id].response[1] , HEX );
425 Serial.print(" ");
426 Serial.print( multiplexData.mbData[id].response[2] , HEX );
427 Serial.print(" A=");
428 Serial.print( varioData->absoluteAlt.value );
429 Serial.print(" V=");
430 Serial.print( mainVspeed.value );
431 Serial.print(" Vo=");
432 Serial.print( valueOrig );
434 Serial.println(" ");
435 #endif
439 //---------------------------------- Here the code to handle the UART
440 #ifdef DEBUG
441 //#define DEBUGSETNEWDATA
442 //#define DEBUGASERIAL
443 #endif
445 #define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr))
447 volatile uint8_t state ; //!< Holds the state of the UART.
448 static volatile unsigned char SwUartTXData ; //!< Data to be transmitted.
449 static volatile unsigned char SwUartTXBitCount ; //!< TX bit counter.
450 static volatile uint8_t SwUartRXData ; //!< Storage for received bits.
451 static volatile uint8_t SwUartRXBitCount ; //!< RX bit counter.
452 static volatile uint8_t TxCount ;
454 volatile uint8_t debugUartRx ;
456 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
457 // in this case, ppm will be wrong and has to be discarded
458 //uint8_t sensorId ;
460 static volatile uint8_t TxMultiplexData[3] ; // array containing the char to transmit (is filled only when a polling address is received
461 //static uint8_t firstMultiplexData ;
462 struct t_mbAllData * volatile ThisMultiplexData = 0 ;
464 ISR(TIMER1_COMPA_vect)
466 switch (state)
468 case TRANSMIT : // startbit has been sent, it is time to output now 8 bits and 1 stop bit
469 #if DEBUGASERIAL
470 PORTC |= 1 ;
471 #endif
472 if( SwUartTXBitCount < 8 ) { // If not 8 bits have been sent
473 if( SwUartTXData & 0x01 ) { // If the LSB of the TX buffer is 1:
474 SET_TX_PIN_MB() ;
475 } else { // Otherwise:
476 CLEAR_TX_PIN_MB() ; // Send a logic 0 on the TX_PIN
478 SwUartTXData = SwUartTXData >> 1 ; // Bitshift the TX buffer and
479 SwUartTXBitCount += 1 ; // increment TX bit counter.
480 } else { //Send stop bit.
481 SET_TX_PIN_MB() ; // Output a logic 1.
482 state = TRANSMIT_STOP_BIT;
484 OCR1A += TICKS2WAITONEMULTIPLEX ; // Count one period into the future.
485 #if DEBUGASERIAL
486 PORTC &= ~1 ;
487 #endif
488 break ;
490 case TRANSMIT_STOP_BIT: //************************************* handling after the stop bit has been sent
491 if ( ++TxCount < 3 ) { // there are 3 bytes to send in the Multiplex interface ?
492 SwUartTXData = TxMultiplexData[TxCount] ;
493 // SwUartTXData = TxCount ;
494 CLEAR_TX_PIN_MB(); // Send a logic 0 on the TX_PIN as start bit
495 OCR1A = TCNT1 + TICKS2WAITONEMULTIPLEX - INTERRUPT_BETWEEN_TRANSMIT; // Count one period into the future.
496 SwUartTXBitCount = 0 ;
497 state = TRANSMIT ;
498 } else { // 3 bytes have already been sent
499 state = WAITING ;
500 // sendStatus = SEND ;
501 OCR1A += DELAY_2000; // 2mS gap before listening
502 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input
503 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is tri-stated.
505 break ;
507 case RECEIVE : // Start bit has been received and we will read bits of data receiving, LSB first.
508 OCR1A += TICKS2WAITONEMULTIPLEX ; // Count one period after the falling edge is trigged.
509 uint8_t data ; // Use a temporary local storage (it saves some bytes (and perhaps time)
510 data = SwUartRXBitCount ;
511 if( data < 8 ) { //If 8 bits are not yet read
512 SwUartRXBitCount = data + 1 ;
513 data = SwUartRXData ;
514 data >>= 1 ; // Shift due to receiving LSB first.
515 if( !(GET_RX_PIN( ) == 0 )) data |= 0x80 ; // If a logical 1 is read, let the data mirror this.
516 SwUartRXData = data ;
517 } else { //Done receiving = 8 bits are in SwUartRXData
518 struct t_mbAllData * volatile pdata = ThisMultiplexData ;
519 FORCE_INDIRECT( pdata ) ;
520 if ( SwUartRXData > MB_MAX_ADRESS ) {
521 // mb_commandReceived ( SwUartRXData ) ; to implement if wanted in a second phase
522 state = WAITING ;
523 OCR1A += DELAY_4000 ; // 4mS gap before listening (take care that 4096 is the max we can wait because timer 1 is 16 bits and prescaler = 1)
524 } else {
525 if ( pdata->mbData[ SwUartRXData ] . active == AVAILABLE ) {
526 TxMultiplexData[0] = pdata->mbData[SwUartRXData].response[0] ;
527 TxMultiplexData[1] = pdata->mbData[SwUartRXData].response[1] ;
528 TxMultiplexData[2] = pdata->mbData[SwUartRXData].response[2] ;
529 if ( (TxMultiplexData[2] != (MB_NOVALUE>>8)) || (TxMultiplexData[1] != (MB_NOVALUE & 0xff)) ) pdata->mbData [ SwUartRXData ] . active = NOT_AVAILABLE ; // this line could be set in comment if we want to send same data and not only when a new calculation is done
530 state = TxPENDING ;
531 OCR1A += ( DELAY_1600 - TICKS2WAITONEMULTIPLEX) ; // 1.6ms gap before sending
532 } else { // Status was not AVAILABLE, so there are no data ready to send
533 state = WAITING ;
534 OCR1A += DELAY_4000 ; // 4mS gap before listening (take care that 4096 is the max we can wait because timer 1 is 16 bits and prescaler = 1)
536 } // end receiving 1 byte
537 } // End receiving 1 bit or 1 byte (8 bits)
538 break ;
540 case TxPENDING : //End of delay before sending data has occurs
541 CLEAR_TX_PIN_MB() ; // Send a start bit (logic 0 on the TX_PIN).
542 OCR1A = TCNT1 + TICKS2WAITONEMULTIPLEX - INTERRUPT_ENTRY_TRANSMIT; // Count one period into the future.
543 SwUartTXBitCount = 0 ;
544 SwUartTXData = TxMultiplexData[0] ;
545 TxCount = 0 ;
546 state = TRANSMIT ;
547 break ;
549 case WAITING : // At the end of wait time, stop timer interrupt but allow pin change interrupt in order to allow to detect incoming data
550 state = IDLE ; // Go back to idle.
551 DISABLE_TIMER_INTERRUPT() ; // Stop the timer interrupts.
552 CLEAR_PIN_CHANGE_INTERRUPT() ; // clear pending pin change interrupt
553 ENABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt enabled
554 #ifdef DEBUG_MULTIPLEX_WITHOUT_RX // When no Rx is connected, oXs has to use only timer interrupts.
555 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
556 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
557 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
558 #endif
559 break ;
561 #ifdef DEBUG_MULTIPLEX_WITHOUT_RX
562 case IDLE : // When there is no RX, there is no pin change interrupt. State is IDLE by default or after sending one set of data
563 // here we will load some dummy data to transmit, wait for 4msec and we will go to TxPending to transmit the data.
564 static uint8_t lineWhenDebugging = 0 ;
565 struct t_mbAllData * volatile pdataDebug;
566 pdataDebug = ThisMultiplexData ;
567 FORCE_INDIRECT( pdataDebug ) ;
568 lineWhenDebugging++ ;
569 if ( lineWhenDebugging > MB_MAX_ADRESS ) lineWhenDebugging = 0 ;
570 if ( pdataDebug->mbData[ lineWhenDebugging ] . active == AVAILABLE ) {
571 TxMultiplexData[0] = pdataDebug->mbData[lineWhenDebugging].response[0] ;
572 TxMultiplexData[1] = pdataDebug->mbData[lineWhenDebugging].response[1] ;
573 TxMultiplexData[2] = pdataDebug->mbData[lineWhenDebugging].response[2] ;
574 pdataDebug->mbData [ lineWhenDebugging ] . active = NOT_AVAILABLE ;
575 // TxMultiplexData[0] = 0x55 ; TxMultiplexData[1] = 0xAA ; TxMultiplexData[2] = 0x55 ; // can be use to measure the timing between bits
576 state = TxPENDING ;
577 OCR1A += DELAY_2000 ;
578 } else { // Status was not AVAILABLE, so there are no data ready to send
579 OCR1A += DELAY_100 ; // 100usec gap before trying again that another data becomes available
581 break ;
582 #endif
584 // Unknown state.
585 default:
586 state = IDLE; // Error, should not occur. Going to a safe state.
587 } // End CASE
588 //#ifdef PPM_INTERRUPT
589 // if ( EIFR & PPM_INT_BIT) ppmInterrupted = 1 ;
590 //#endif
592 } // End of ISR
596 //brief Function to initialize the UART for multiplex protocol
597 // This function will set up pins to transmit and receive on. Control of Timer1 and pin change interrupt 0.
598 void initMultiplexUart( struct t_mbAllData * volatile pdata ) //*************** initialise UART for Multiplex
600 ThisMultiplexData = pdata ; // this allows the ISR routine to get access to the data in OXS_Out_Multiplex
602 //PORT
603 TRXDDR &= ~( 1 << PIN_SERIALTX ) ; // PIN is input.
604 TRXPORT &= ~( 1 << PIN_SERIALTX ) ; // PIN is tri-stated.
606 // External interrupt
608 #if PIN_SERIALTX == 4
609 PCMSK2 |= 0x10 ; // IO4 (PD4) on Arduini mini
610 #elif PIN_SERIALTX == 2
611 PCMSK2 |= 0x04 ; // IO2 (PD2) on Arduini mini
612 #else
613 #error "This PIN is not supported"
614 #endif
615 CLEAR_PIN_CHANGE_INTERRUPT() ;
616 ENABLE_PIN_CHANGE_INTERRUPT() ;
617 state = IDLE ; // Internal State Variable
619 #if DEBUGASERIAL
620 DDRC = 0x01 ; // PC0 as o/p debug = pin A0 !!!!
621 PORTC = 0 ;
622 #endif
624 #ifdef DEBUG_MULTIPLEX_WITHOUT_RX // in this debug case, we have to enable timer interrupt without waiting for a pin change interrupt.
625 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
626 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
627 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
628 #endif
632 // ! \brief External interrupt service routine. ********************
633 // Interrupt on Pin Change to detect change on level on Multiplex signal (= could be a start bit)
635 // The falling edge in the beginning of the start
636 // bit will trig this interrupt. The state will
637 // be changed to RECEIVE, and the timer interrupt
638 // will be set to trig one and a half bit period
639 // from the falling edge. At that instant the
640 // code should sample the first data bit.
642 // note initMultiplexUart( void ) must be called in advance.
644 // This is the pin change interrupt for port D
645 // This assumes it is the only pin change interrupt
646 // on this port
648 ISR(PCINT2_vect)
650 if (!( TRXPIN & ( 1 << PIN_SERIALTX ) )) { // Pin is low = start bit
651 DISABLE_PIN_CHANGE_INTERRUPT() ; // pin change interrupt disabled
652 state = RECEIVE ; // Change state
653 DISABLE_TIMER_INTERRUPT() ; // Disable timer to change its registers.
654 OCR1A = TCNT1 + TICKS2WAITONE_HALFMULTIPLEX - INTERRUPT_EXEC_CYCL - INTERRUPT_EARLY_BIAS ; // Count one and a half period into the future.
655 #if DEBUGASERIAL
656 PORTC |= 1 ;
657 #endif
658 SwUartRXBitCount = 0 ; // Clear received bit counter.
659 CLEAR_TIMER_INTERRUPT() ; // Clear interrupt bits
660 ENABLE_TIMER_INTERRUPT() ; // Enable timer1 interrupt on again
662 //#ifdef PPM_INTERRUPT
663 // if ( EIFR & PPM_INT_BIT) ppmInterrupted = 1 ;
664 //#endif
666 } // end ISR pin change
671 // -------------------------End of Multiplex protocol--------------------------------------------------------------------------------------
673 #endif // END of MULTIPLEX