Subversion Repositories HomeAutomation

Rev

Rev 638 | Go to most recent revision | 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 CALIBRATE_AZIMUTH 0 // EEPROM adress
  33.  
  34. // Make sure this is a power of 2
  35. #define AVERAGE_SIZE 16
  36. #define AVERAGE_SIZE_SHIFT 4
  37.  
  38. // Tillfälliga defines
  39. #define MSG_CAL_SET 0x0100001UL
  40. #define MSG_CAL_GET 0x0100002UL
  41. #define MSG_ABS 0x01000031UL
  42. #define MSG_REL 0x0100004UL
  43. #define MSG_START 0x0100005UL
  44. #define MSG_STOP 0x0100006UL
  45. #define MSG_STATUS 0x0100007UL
  46.  
  47.  
  48. // ----------
  49.  
  50. // Essential pins
  51. // 0: PD2 azimuth plus
  52. // 1: PD1 azimuth minus
  53. // 8: PC4 ADC4 azimuth feedback
  54.  
  55.  
  56.  
  57. // A simple message "queue", with space for one message only.
  58. // These are declared volatile to tell the compiler not to optimize away accesses.
  59. volatile Can_Message_t rxMsg; // Message storage
  60. volatile uint8_t rxMsgFull;   // Synchronization flag
  61.  
  62. //uint16_t actualElevationValue;
  63. //uint16_t desiredElevationValue;
  64. //uint16_t actualAzimuthValue;
  65. //uint16_t desiredAzimuthValue;
  66.  
  67. // For calculating average feedback measurement
  68. uint16_t azimuthReadout[ AVERAGE_SIZE ];
  69. //uint16_t elevationReadout[ AVERAGE_SIZE];
  70.  
  71. uint16_t azimuthCalibration;
  72.  
  73. // CAN message reception callback.
  74. // This function runs with interrupts disabled, keep it as short as possible.
  75. void can_receive( Can_Message_t *msg ) {
  76.     if (!rxMsgFull) {
  77.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  78.         rxMsgFull = 1;
  79.     }
  80. }
  81.  
  82. // Calibration function
  83. // mode: set / get
  84. // value:
  85. int16_t calibration( uint8_t mode, uint16_t value );
  86.  
  87. // Turn rotor
  88. // position: 0-1024
  89. uint8_t turn( uint16_t position );
  90.  
  91. // Get position
  92. // Gets the average value for compensation of distorsions
  93. uint16_t getPosition( void );
  94.  
  95. // Initiate ADC
  96. void initAdcFeedback( void );
  97.  
  98. // Read antenna feedback from ADC
  99. void readFeedback( void );
  100.  
  101. // Control rotation relays
  102. void controlRelay( uint8_t direction );
  103.  
  104. // Sends antennas position on CAN
  105. void sendStatus( void );
  106.  
  107.  
  108. int main( void )
  109. {
  110.     // Enable interrupts as early as possible
  111.     sei();
  112.    
  113.     Timer_Init();
  114.    
  115.     // Setup ADC
  116.     initAdcFeedback();
  117.    
  118.     Can_Message_t txMsg;
  119.     txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  120.     txMsg.DataLength = 4;
  121.     txMsg.RemoteFlag = 0;
  122.     txMsg.ExtendedFlag = 1;
  123.     txMsg.Data.words[0] = APP_TYPE;
  124.     txMsg.Data.words[1] = APP_VERSION;
  125.    
  126.     // Set up callback for CAN reception, this is optional if only sending is required.
  127.     BIOS_CanCallback = &can_receive;
  128.     // Send CAN_NMT_APP_START
  129.     BIOS_CanSend(&txMsg);
  130.    
  131.     // Read calibration value from eeprom
  132.     azimuthCalibration = eeprom_read_word( CALIBRATE_AZIMUTH );
  133.    
  134.     // Timer for reading position feedback
  135.     Timer_SetTimeout(0, 50, TimerTypeFreeRunning, 0);
  136.  
  137.    
  138.     while (1) {
  139.         if (Timer_Expired(0)) {
  140.             // Periodicly read antennas position
  141.             readFeedback();
  142.         }
  143.        
  144.         if (rxMsgFull) {
  145.  
  146.             switch (rxMsg.Id){
  147.                 case MSG_CAL_SET: // Set calibration value
  148.                     if( 2 == rxMsg.DataLength ){
  149.                         calibration( SET, rxMsg.Data.words[0] );
  150.                     }
  151.                     break;
  152.                    
  153.                 case MSG_CAL_GET: // Get calibration value
  154.                     if( 0 == rxMsg.DataLength ){
  155.                        
  156.                     }
  157.                     break;
  158.                    
  159.                 case MSG_ABS: // Start turning to absolute position
  160.                     if( 2 == rxMsg.DataLength ){
  161.                        
  162.                     }
  163.                     break;
  164.                    
  165.                 case MSG_REL: // Start turning to relative position
  166.                     if( 2 == rxMsg.DataLength ){
  167.                        
  168.                     }
  169.                     break;
  170.                    
  171.                 case MSG_START: // Start turning
  172.                     if( 1 == rxMsg.DataLength ){
  173.                         // First data byte decides direction
  174.                         controlRelay( rxMsg.Data.bytes[0] );
  175.                     }
  176.                     break;
  177.                    
  178.                 case MSG_STOP: // Stop turning
  179.                     if( 1 == rxMsg.DataLength ){
  180.                         controlRelay( ROTATE_STOP );
  181.                     }
  182.                     break;
  183.                 case MSG_STATUS: // Get position
  184.                     if( 0 == rxMsg.DataLength ){
  185.                         sendStatus();
  186.                     }
  187.                     break;
  188.                    
  189.                 default:
  190.                     break;
  191.             }
  192.  
  193.             rxMsgFull = 0; //  
  194.         }
  195.     }
  196.    
  197.     return 0;
  198. }
  199.  
  200.  
  201. int16_t calibration( uint8_t mode, uint16_t value )
  202. {
  203.     // set / get calibration value
  204.     if( SET == mode ){
  205.         eeprom_write_word( CALIBRATE_AZIMUTH, value );
  206.         azimuthCalibration = value;
  207.    
  208.     }else if( GET == mode ){
  209.         return azimuthCalibration;
  210.     }
  211.     return 0;
  212. }
  213.  
  214. uint8_t turn( uint16_t position )
  215. {
  216.     // start relay
  217.     // read feedback
  218.     // callibrate measurement
  219.    
  220.     while(0){
  221.        
  222.     }
  223.     return 0;
  224. }
  225.  
  226. uint16_t getPosition( void )
  227. {
  228.     uint16_t position = 0;
  229.    
  230.     // Get average value of position
  231.     for( uint8_t i=0; i < AVERAGE_SIZE; i++ ){
  232.         position += azimuthReadout[i];
  233.     }
  234.    
  235.     position = position >> AVERAGE_SIZE_SHIFT;
  236.     position += azimuthCalibration;
  237.    
  238.     return position;
  239. }
  240.  
  241. void initAdcFeedback( void )
  242. {
  243.     // ADC4: Azimuth feedback
  244.    
  245.     // Enable ADC4
  246.     ADMUX |= ( 1 << MUX2 );
  247.     ADMUX &= ~(( 1 << MUX0 )|( 1 << MUX1 )|( 1 << MUX3 ));
  248.  
  249.     // Prescaler /128
  250.     ADCSRA |= ( 1 << ADPS2)|( 1 << ADPS1)|( 1 << ADPS0);
  251.    
  252.     // Enable AVcc as Voltage Reference
  253.     ADMUX |= ( 1 << REFS0 );
  254.     ADMUX &= ~( 1 << REFS1 );
  255.    
  256.     // Right adjust the result
  257.     ADMUX &= ~( 1 << ADLAR );
  258.    
  259. //  // Auto Trigger
  260. //  ADCSRA |= ( 1 << ADATE );
  261.    
  262.     // Disable digital input
  263.     DIDR0 |= ( 1 << ADC5D )|( 1 << ADC4D );
  264.    
  265.     // Wake up ADC and enable it
  266.     PRR &= ~( 1 << PRADC );
  267.     ADCSRA |= ( 1 << ADEN );
  268.    
  269.     // Start first conversion
  270.     ADCSRA |= ( 1 << ADSC );
  271. }
  272.  
  273. void controlRelay( uint8_t direction )
  274. {
  275.     if( ROTATE_PLUS == direction ){ // Turn clockwise
  276.         PORTD &= ~(1 << PD2);
  277.         PORTD |= (1 << PD1);
  278.     }else if ( ROTATE_MINUS == direction ){ // Turn counter clockwise
  279.         PORTD &= ~(1 << PD1);
  280.         PORTD |= (1 << PD2);
  281.     }else{
  282.         // Stop azimuth rotor
  283.         PORTD |= (1 << PD1);
  284.         PORTD |= (1 << PD2);
  285.     }
  286. }
  287.  
  288. void readFeedback( void )
  289. {
  290.     static uint8_t azimuthArrayPosition = 0;
  291.  
  292.     while( ADCSRA & ( 1 << ADSC )){} // Wait for conversion to complete
  293.    
  294.     azimuthReadout[ azimuthArrayPosition ] = ADCW;
  295.     azimuthArrayPosition++;
  296.     if( AVERAGE_SIZE <= azimuthArrayPosition ){
  297.         azimuthArrayPosition = 0;
  298.     }
  299.    
  300.     // Start next conversion
  301.     ADCSRA |= ( 1 << ADSC );
  302. }
  303.  
  304. void sendStatus( void )
  305. {
  306.     Can_Message_t txMsg;
  307.    
  308.     txMsg.Id = 0x01fff00UL; //(( 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 );
  309.    
  310.     txMsg.DataLength = 2;
  311.     txMsg.RemoteFlag = 0;
  312.     txMsg.ExtendedFlag = 1;
  313.    
  314.     txMsg.Data.words[ 0 ] = getPosition();
  315.    
  316.     BIOS_CanSend( &txMsg );
  317.    
  318. }
  319.