Subversion Repositories HomeAutomation

Rev

Rev 731 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * AntennaControl
  3.  *
  4.  * Build for use at ETA, http://www.eta.chalmers.se/, controlling their 2 meter yagi antenna.
  5.  *
  6.  * @date 2007-10-28
  7.  * @author Erik Larsson
  8.  *
  9.  */
  10.  
  11. #include <inttypes.h>
  12. #include <avr/interrupt.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <avr/eeprom.h>
  16. #include <config.h> // All configuration parameters
  17. #include <bios.h>   // BIOS interface declarations, including CAN structure and ID defines.
  18. #include <drivers/timer/timer.h>
  19.  
  20. #define APP_TYPE    0xf0a0
  21. #define APP_VERSION 0x0001
  22.  
  23. #define AZIMUTH 0
  24.  
  25. #define ROTATE_STOP 0
  26. #define ROTATE_PLUS 1
  27. #define ROTATE_MINUS 2
  28.  
  29. #define SET 0
  30. #define GET 1
  31.  
  32. #define STATUS 0
  33.  
  34. #define CALIBRATE_AZIMUTH 0 // EEPROM adress
  35.  
  36. // Make sure this is a power of 2
  37. #define AVERAGE_SIZE 16
  38. #define AVERAGE_SIZE_SHIFT 4
  39.  
  40. // Tillfälliga defines
  41. #define MSG_CAL_SET 0x11100001UL
  42. #define MSG_CAL_GET 0x11100002UL
  43. #define MSG_ABS 0x111000031UL
  44. #define MSG_REL 0x11100004UL
  45. #define MSG_START 0x11100005UL
  46. #define MSG_STOP 0x11100006UL
  47. #define MSG_STATUS 0x11100007UL
  48.  
  49. #define MSG_CAL_RET 0x111000f2UL
  50.  
  51.  
  52. // ----------
  53.  
  54. // Essential pins
  55. // 0: PD2 azimuth plus
  56. // 1: PD1 azimuth minus
  57. // 8: PC4 ADC4 azimuth feedback
  58.  
  59.  
  60.  
  61. // A simple message "queue", with space for one message only.
  62. // These are declared volatile to tell the compiler not to optimize away accesses.
  63. volatile Can_Message_t rxMsg; // Message storage
  64. volatile uint8_t rxMsgFull;   // Synchronization flag
  65.  
  66. //uint16_t actualElevationValue;
  67. //uint16_t desiredElevationValue;
  68. //uint16_t actualAzimuthValue;
  69. //uint16_t desiredAzimuthValue;
  70.  
  71. // For calculating average feedback measurement
  72. uint16_t azimuthReadout[ AVERAGE_SIZE ];
  73.  
  74. uint16_t azimuthCalibration;
  75.  
  76. // CAN message reception callback.
  77. // This function runs with interrupts disabled, keep it as short as possible.
  78. void can_receive( Can_Message_t *msg ) {
  79.     if (!rxMsgFull) {
  80.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  81.         rxMsgFull = 1;
  82.     }
  83. }
  84.  
  85. // Calibration function
  86. // mode: set / get
  87. // value:
  88. int16_t calibration( uint8_t mode, uint16_t value );
  89.  
  90. // Turn rotor
  91. // position: 0-1024
  92. uint8_t turn( uint16_t position );
  93.  
  94. // Get position
  95. // Gets the average value for compensation of distorsions
  96. uint16_t getPosition( void );
  97.  
  98. // Initiate ADC
  99. void initAdcFeedback( void );
  100.  
  101. // Read antenna feedback from ADC
  102. void readFeedback( void );
  103.  
  104. // Control rotation relays
  105. void controlRelay( uint8_t direction );
  106.  
  107. // Sends antennas position on CAN
  108. void sendStatus( uint8_t type );
  109.  
  110.  
  111. int main( void )
  112. {
  113.     // Enable interrupts as early as possible
  114.     sei();
  115.    
  116.     Timer_Init();
  117.  
  118.     // Set as outputs and stop rotor
  119.     DDRD |= (1 << PD1)|(1 << PD2);
  120.     PORTD &= ~((1 << PD1)|(1 << PD2));
  121.    
  122.     // Setup ADC
  123.     initAdcFeedback();
  124.    
  125.     Can_Message_t txMsg;
  126.     txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  127.     txMsg.DataLength = 4;
  128.     txMsg.RemoteFlag = 0;
  129.     txMsg.ExtendedFlag = 1;
  130.     txMsg.Data.words[0] = APP_TYPE;
  131.     txMsg.Data.words[1] = APP_VERSION;
  132.    
  133.     // Set up callback for CAN reception
  134.     BIOS_CanCallback = &can_receive;
  135.     // Send CAN_NMT_APP_START
  136.     BIOS_CanSend(&txMsg);
  137.    
  138.     // Read calibration value from eeprom
  139.     azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
  140.    
  141.     // Timer for reading position feedback
  142.     Timer_SetTimeout(0, 100, TimerTypeFreeRunning, 0);
  143.     Timer_SetTimeout(1, 1000, TimerTypeFreeRunning, 0);
  144.  
  145.     sendStatus( STATUS );
  146.  
  147.     while (1) {
  148.         if (Timer_Expired(0)) {
  149.             // Periodicly read antennas position
  150.             readFeedback();
  151.         }
  152.         if (Timer_Expired(1)) {
  153.             sendStatus(STATUS);
  154.         }
  155.        
  156.         if (rxMsgFull) {
  157.             switch (rxMsg.Id){
  158.                 case MSG_CAL_SET: // Set calibration value
  159.                     if( 2 == rxMsg.DataLength ){
  160.                         calibration( SET, rxMsg.Data.words[0] );
  161.                     }
  162.                     break;
  163.                    
  164.                 case MSG_CAL_GET: // Get calibration value
  165.                     if( 0 == rxMsg.DataLength ){
  166.                         txMsg.Id = MSG_CAL_RET;
  167.                         txMsg.DataLength = 2;
  168.                         txMsg.Data.words[0] = calibration( GET, 0 );
  169.                         BIOS_CanSend(&txMsg);
  170.                     }
  171.                     break;
  172.                    
  173.                 case MSG_ABS: // Start turning to absolute position
  174.                     if( 2 == rxMsg.DataLength ){
  175.                        
  176.                     }
  177.                     break;
  178.                    
  179.                 case MSG_REL: // Start turning to relative position
  180.                     if( 2 == rxMsg.DataLength ){
  181.                        
  182.                     }
  183.                     break;
  184.                    
  185.                 case MSG_START: // Start turning
  186.                     if( 1 == rxMsg.DataLength ){
  187.                         // First data byte decides direction
  188.                         controlRelay( rxMsg.Data.bytes[0] );
  189.                     }
  190.                     break;
  191.                    
  192.                 case MSG_STOP: // Stop turning
  193.                     //if( 1 == rxMsg.DataLength ){
  194.                         controlRelay( ROTATE_STOP );
  195.                     //}
  196.                     break;
  197.                 case MSG_STATUS: // Get position
  198.                     if( 0 == rxMsg.DataLength ){
  199.                         sendStatus(STATUS);
  200.                     }
  201.                     break;
  202.                    
  203.                 default:
  204.                     break;
  205.             }
  206.  
  207.                 rxMsgFull = 0; //  
  208.         }
  209.     }
  210.    
  211.     return 0;
  212. }
  213.  
  214.  
  215. int16_t calibration( uint8_t mode, uint16_t value )
  216. {
  217.     // set / get calibration value
  218.     if( SET == mode ){
  219.         eeprom_write_word( CALIBRATE_AZIMUTH, value );
  220.         azimuthCalibration = value;
  221.    
  222.     }else if( GET == mode ){
  223.         return azimuthCalibration;
  224.     }
  225.     return 0;
  226. }
  227.  
  228. uint8_t turn( uint16_t position )
  229. {
  230.     // start relay
  231.     // read feedback
  232.     // callibrate measurement
  233.    
  234.     while(0){
  235.        
  236.     }
  237.     return 0;
  238. }
  239.  
  240. uint16_t getPosition( void )
  241. {
  242.     uint16_t position = 0;
  243.  
  244.     // Get average value of position
  245.     for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
  246.         position += azimuthReadout[i];
  247.     }
  248.    
  249.     // Calculate average
  250.     position = position >> AVERAGE_SIZE_SHIFT;
  251.  
  252.     // Convert to degrees, gives about 361 degrees
  253.     // start 508, stop 1023 => 516 bits per rotation
  254.     // 516 * 7 / 10 = 361
  255.  
  256.     // Antennen rör sig inom 180 -> 360 (=0) -> 180
  257.     // Norr = mittläget = 0 / 360 grader = 766 decimalt innan omräkning
  258.     // Söder = ändlägena = 180 grader = 508 och 1023 innan omräkning
  259.  
  260.  
  261.     // Make it between 508 and 1023
  262.     if( position < 508 ){
  263.         position = 0;
  264.     }else{
  265.         position -= 508;
  266.     }
  267.    
  268. //  if( 0x8000&position ){
  269. //      position = -position;
  270. //      position *= 7;
  271. //      position /= 10;
  272. //      //position = -position;
  273. //  }else{
  274.  
  275.         // Make it between 0 and 360
  276.         position *= 7;
  277.         position /= 10;
  278. //  }
  279.  
  280.     // Move it to 180 and 540
  281.     position += 180;
  282.    
  283.     // Calibrate
  284.     position += (int16_t)azimuthCalibration;
  285.    
  286.     // North is now at 360
  287.     if( position > 360 ){
  288.         // Antenna is between 0 and 180
  289.         position -= 360;
  290.     }
  291.    
  292.     return position;
  293. }
  294.  
  295. void initAdcFeedback( void )
  296. {
  297.     // ADC4: Azimuth feedback
  298.    
  299.     // Enable ADC4
  300.     ADMUX |= ( 1 << MUX2 );
  301.     ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
  302.  
  303.     // Prescaler /128
  304.     ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
  305.    
  306.     // Enable AVcc as Voltage Reference
  307.     ADMUX |= ( 1 << REFS0 );
  308.     ADMUX &= ~( 1 << REFS1 );
  309.    
  310.     // Right adjust the result
  311.     ADMUX &= ~( 1 << ADLAR );
  312.    
  313.     // Disable digital input
  314.     DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
  315.    
  316.     // Wake up ADC and enable it
  317.     PRR &= ~( 1 << PRADC );
  318.     ADCSRA |= ( 1 << ADEN );
  319.    
  320.     // Start first conversion
  321.     ADCSRA |= ( 1 << ADSC );
  322. }
  323.  
  324. void controlRelay( uint8_t direction )
  325. {
  326.     if( ROTATE_PLUS == direction ){ // Turn clockwise
  327.         PORTD &= ~(1 << PD1);
  328.         PORTD |= (1 << PD2);
  329.     }else if ( ROTATE_MINUS == direction ){ // Turn counter clockwise
  330.         PORTD &= ~(1 << PD2);
  331.         PORTD |= (1 << PD1);
  332.     }else{
  333.         // Stop azimuth rotor
  334.         PORTD &= ~(1 << PD1);
  335.         PORTD &= ~(1 << PD2);
  336.     }
  337. }
  338.  
  339. void readFeedback( void )
  340. {
  341.     static uint8_t azimuthArrayPosition = 0;
  342.  
  343.     while( ADCSRA & ( 1 << ADSC )){} // Wait for conversion to complete
  344.    
  345.     azimuthReadout[ azimuthArrayPosition ] = ADCW; // Store result in ring buffer
  346.     azimuthArrayPosition++;
  347.     if( AVERAGE_SIZE <= azimuthArrayPosition ){
  348.         azimuthArrayPosition = 0;
  349.     }
  350.  
  351.     // Start next conversion
  352.     ADCSRA |= ( 1 << ADSC );
  353. }
  354.  
  355. void sendStatus( uint8_t type )
  356. {
  357.     Can_Message_t txMsg;
  358.    
  359.     //txMsg.Id = 0x1f8f0100UL; //(( CAN_SNS << CAN_SHIFT_CLASS )|( SNS_TYPE_STATUS << CAN_SHIFT_SNS_TYPE )|( SNS_ID_ANTENNA_STATUS << CAN_SHIFT_SNS_ID )|( NODE_ID << CAN_SHIFT_SNS_SID );
  360.    
  361.     txMsg.DataLength = 2;
  362.     txMsg.RemoteFlag = 0;
  363.     txMsg.ExtendedFlag = 1;
  364.    
  365. //  txMsg.Data.words[ 0 ] = getPosition();
  366.  
  367.     if(STATUS == type){
  368.         txMsg.Id = 0x1f8f0100UL;
  369.         txMsg.Data.words[ 0 ] = getPosition();
  370.         txMsg.DataLength = 2;
  371.     }else{
  372.         txMsg.Id = 0x12020202UL;
  373.         txMsg.Data.bytes[ 0 ] = type;
  374.         txMsg.DataLength = 1;
  375.     }
  376.  
  377.     // Try to resend up to four times
  378.     for(int i=0; i<3;i++){
  379.         if( CAN_OK == BIOS_CanSend( &txMsg )){
  380.             return;
  381.         }
  382.     }      
  383.    
  384. }
  385.