Subversion Repositories HomeAutomation

Rev

Rev 317 | Rev 322 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * CanBlinds.
  3.  * Takes incomming packages and adjusts PWM output.
  4.  * Input: -128 to +127
  5.  * Position msg: <byte0 BLINDS_CMD> <byte1 position> <byte2 servo number>
  6.  * Turning msg: <byte0 START/STOP> <byte 1 direction> <byte2 servo number>
  7.  *
  8.  * @date    2007-01-01
  9.  * @author  Erik Larsson
  10.  *
  11.  */
  12.  
  13. //#define TWO_BUTTON_MODE /* If using two (or just one but nothing more) auxiliary buttons */
  14.  
  15. /*-----------------------------------------------------------------------------
  16.  * Includes
  17.  *---------------------------------------------------------------------------*/
  18. /* system files */
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <stdio.h>
  22. /* lib files */
  23. #include <bios.h>
  24. #include <tc1047.h>
  25. #include <rc_servo.h>
  26.  
  27. #include <eqlazer_funcdefs.h>
  28.  
  29. /* defines */
  30. #define NODE_ID     0x03L // FIXME ändras för varje nod
  31. #define GROUP_ID    0x01L // ^
  32.  
  33. #define FAILSAFE_MODE       0x0F
  34. #define FAILSAFE_TRESHOLD   60  /* Degrees celcius when nodeBlinds goes into failsafe mode */
  35.  
  36. #define BLINDS_CMD_ABS      0x01 /* Absolute position */
  37. #define BLINDS_CMD_REL      0x02 /* Relative position */
  38. #define BLINDS_CMD_START    0x03 /* Start turning RC-servo */
  39. #define BLINDS_CMD_STOP     0x04 /* Stop turning RC-servo */
  40. #define BLINDS_CMD_RESET    0x05
  41. #define BLINDS_CMD_STATUS   0x06
  42.  
  43. #define BLINDS_TURN_STOP    0x00
  44. #define BLINDS_TURN_LEFT    0x01
  45. #define BLINDS_TURN_RIGHT   0x02
  46.  
  47. #define STEPS_PER_TURN_PERIOD   10 /* number of steps for each adjustment */
  48. #define TURN_PERIOD             100 /* ms */
  49. #define STATUS_SEND_PERIOD      5000 /* ms */
  50. #define FAILSAFE_SEND_PERIOD    10000 /* ms */
  51. #define BOUNCE_TIME             10 /* ms */
  52. #define SERVO_FEED_TIME         2000 /* ms */
  53. #define BUTTON1                 1
  54. #define BUTTON2                 2
  55.  
  56. #define TRUE 1
  57. #define FALSE !TRUE
  58.  
  59. /*-------------------------------------------------------------------------
  60.  * Global variables
  61.  * -----------------------------------------------------------------------*/
  62. /*#if defined(TWO_BUTTON_MODE)
  63. Can_Message_t txMsg_Button;
  64. #endif*/
  65.  
  66. uint8_t msg_received = FALSE;
  67.  
  68. Can_Message_t txMsg;
  69. Can_Message_t rxMsg;
  70.  
  71. /*----------------------------------------------------------------------------
  72.  * Functions
  73.  * -------------------------------------------------------------------------*/
  74. void blindsFailsafe();
  75.  
  76. /* Takes care about incoming messages and parses them if this node is adressed */
  77. void can_receive(Can_Message_t *msg){
  78.     uint32_t act;
  79.     uint8_t m, act_type, group, node;
  80.     if( ((msg->Id & CLASS_MASK) >> CLASS_MASK_BITS) == CLASS_ACT ){
  81.         /* Parse message */
  82.         act = (msg->Id & TYPE_MASK) >> TYPE_MASK_BITS;
  83.         act_type = (act & ACT_TYPE_MASK) >> ACT_TYPE_BITS;
  84.         group = (act & ACT_GROUP_MASK) >> ACT_GROUP_BITS;
  85.         node = (act & ACT_NODE_MASK) >> ACT_NODE_BITS;
  86.  
  87.         /* Check if it is command to control this servo */
  88.         if(act_type == ACT_TYPE_SERVO){
  89.             if(group == GROUP_ID || node == NODE_ID){
  90.                 for(m=0;m<msg->DataLength;m++){
  91.                     rxMsg.Data.bytes[m] = msg->Data.bytes[m];
  92.                 }
  93.                 msg_received = TRUE;
  94.             }
  95.         }
  96.     }
  97. }
  98.  
  99. /*----------------------------------------------------------------------------
  100.  * Interrupt routines
  101.  * -------------------------------------------------------------------------*/
  102. #if defined(TWO_BUTTON_MODE)
  103. #error two button mode is still untested
  104. ISR( PCINT2_vect )
  105. {
  106.     /*
  107.      * Auxiliary button pressed and released
  108.      * Check time between press and release to eliminate bounces
  109.      */
  110.     static uint32_t buttonTime[2];
  111.  
  112.     txMsg_Button.RemoteFlag = 0;
  113.     txMsg_Button.ExtendedFlag = 1;
  114.  
  115.     if( (PIND & (1<<PD1)) == 0){
  116.         /* Button pressed */
  117.         buttonTime[0] = Timebase_CurrentTime();
  118.     }else if( (PIND & (1<<PD1)) == 1){
  119.         if( Timebase_PassedTimeMillis( buttonTime[0] ) >= BOUNCE_TIME ){
  120.             /* No bounce, send message */
  121.             txMsg_Button.Id = BUTTON_ID;
  122.             txMsg_Button.DataLength = 1;
  123.             txMsg_Button.Data.bytes[0] = BUTTON1;
  124.             return;
  125.         }else{
  126.             /* Just bounces, ignore it */
  127.             return;
  128.         }
  129.     }
  130.     if( (PIND & (1<<PD2)) == 0){
  131.         /* Button pressed */
  132.         buttonTime[1] = Timebase_CurrentTime();
  133.     }else if( (PIND & (1<<PD2)) == 1){
  134.         if( Timebase_PassedTimeMillis( buttonTime[1] ) >= BOUNCE_TIME ){
  135.             /* No bounce, send message */
  136.             txMsg_Button.Id = BUTTON_ID;
  137.             txMsg_Button.DataLength = 1;
  138.             txMsg_Button.Data.bytes[0] = BUTTON2;
  139.             return;
  140.         }else{
  141.             /* Just bounces, ignore it */
  142.             return;
  143.         }
  144.     }
  145. }
  146. #endif
  147.  
  148. /*-----------------------------------------------------------------------------
  149.  * Main Program
  150.  *---------------------------------------------------------------------------*/
  151. int main(void) {
  152.  
  153.     uint8_t //blindsStatus, /* Position (-128 to 127) */
  154.             servoToTurn,
  155.             turnDirection = BLINDS_TURN_STOP; /* Specifies direction to turn or stopped */
  156.     uint32_t boardTemperature = 0;
  157.     uint32_t timeStamp = 0, timeStampTurn = 0, servoFeed_timeStamp = 0;
  158.  
  159.     sei();
  160.     adcTemperatureInit();
  161.     rcServoInit();
  162.  
  163. #if defined(TWO_BUTTON_MODE)
  164.     /*
  165.      * Initialize buttons
  166.      * It is possible to use ie. sensors instead
  167.      * but then change this
  168.      */
  169.     /* Set as input and enable pull-up */
  170.     DDRD &= ~( (1<<DDD1)|(1<<DDD2) );
  171.     PORTD |= (1<<PD1)|(1<<PD2);
  172.  
  173.     /* Enable IO-pin interrupt */
  174.     PCICR |= (1<<PCIE2);
  175.     /* Unmask PD1 and PD2 */
  176.     PCMSK2 |= (1<<PCINT16) | (1<<PCINT17);
  177. #endif
  178.     /* Set output and turn off the servo current feed */
  179.     DDRC |= (1<<DDC0);
  180.     PORTC &= ~(1<<PC0);
  181.  
  182. //  sei();
  183.  
  184.     txMsg.RemoteFlag = 0;
  185.     txMsg.ExtendedFlag = 1;
  186.     txMsg.Id = (CLASS_SNS << CLASS_MASK_BITS)|(SNS_ACT_STATUS_SERVO << TYPE_MASK_BITS)|(NODE_ID << SID_MASK_BITS);
  187.  
  188.     /* Set up callback for CAN messages */
  189.     bios->can_callback = &can_receive;
  190.  
  191.     /* main loop */
  192.     while (1) {
  193.         /* check if any messages have been received */
  194.         if(msg_received){
  195.             /* This node that control a servo is adressed */
  196.  
  197.             if( rxMsg.Data.bytes[0] == BLINDS_CMD_ABS ){
  198.                 /* Set absolute position to servo */
  199.                 setPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
  200.                 timeStampTurn = bios->timebase_get();
  201.  
  202.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_REL){
  203.                 /* Set relative position to servo */
  204.                 alterPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
  205.                 timeStampTurn = bios->timebase_get();
  206.  
  207.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_START ){
  208.                 /* Start turning the servo */
  209.                 turnDirection = rxMsg.Data.bytes[1];
  210.                 servoToTurn = rxMsg.Data.bytes[2];
  211.                 timeStampTurn = bios->timebase_get();
  212.  
  213.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STOP ){
  214.                 /* Stop turning */
  215.                 turnDirection = BLINDS_TURN_STOP;
  216.  
  217.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STATUS){
  218.                 /* Send blinds status to CAN */
  219.                 boardTemperature = getTC1047temperature();
  220.  
  221.                 if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  222.                     blindsFailsafe();
  223.                 }else{
  224.                     txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  225.                     txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  226.                     txMsg.Data.bytes[2] = 0x00;
  227. #if NUMBER_OF_RCS >0
  228.                     txMsg.Data.bytes[3] = getPosition(1);
  229. #endif
  230. #if NUMBER_OF_RCS >1
  231.                     txMsg.Data.bytes[4] = getPosition(2);
  232. #endif
  233. #if NUMBER_OF_RCS >2
  234.                     txMsg.Data.bytes[5] = getPosition(3);
  235. #endif
  236.                     txMsg.DataLength = NUMBER_OF_RCS+3;
  237.                     bios->can_send(&txMsg);
  238.                     }
  239.                 }
  240.                 msg_received = FALSE;
  241.         }
  242.  
  243.         if( (bios->timebase_get() - timeStamp)  >= STATUS_SEND_PERIOD ){
  244.             timeStamp = bios->timebase_get();
  245.             /* Send blinds status to CAN */
  246.  
  247.             boardTemperature = getTC1047temperature();
  248.  
  249.             if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  250.                 blindsFailsafe();
  251.             }else{
  252.                 txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  253.                 txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  254.                 txMsg.Data.bytes[2] = 0x00;
  255. #if NUMBER_OF_RCS >0
  256.                 txMsg.Data.bytes[3] = getPosition(1);
  257. #endif
  258. #if NUMBER_OF_RCS >1
  259.                 txMsg.Data.bytes[4] = getPosition(2);
  260. #endif
  261. #if NUMBER_OF_RCS >2
  262.                 txMsg.Data.bytes[5] = getPosition(3);
  263. #endif
  264.                 txMsg.DataLength = NUMBER_OF_RCS+3;
  265.  
  266.                 bios->can_send(&txMsg);
  267.             }
  268.         }
  269.         /* If start turning servo */
  270.         if( turnDirection ){
  271.             if( bios->timebase_get() - timeStampTurn >= TURN_PERIOD ){
  272.                 timeStampTurn = bios->timebase_get();
  273.                 /* Clockwise or counterclockwise? */
  274.                 if( turnDirection == BLINDS_TURN_LEFT ){
  275.                     alterPosition( -STEPS_PER_TURN_PERIOD , servoToTurn);
  276.                 }else if( turnDirection == BLINDS_TURN_RIGHT ){
  277.                     alterPosition( STEPS_PER_TURN_PERIOD , servoToTurn);
  278.                 }
  279.             }
  280.         }
  281.         /* Turn off the servo current feed */
  282.         if( bios->timebase_get() - servoFeed_timeStamp >= SERVO_FEED_TIME ){
  283.             PORTC &= ~(1<<PC0);
  284.         }else{
  285.             PORTC |= (1<<PC0);
  286.         }
  287.     }
  288.     return 0;
  289. }
  290.  
  291. void blindsFailsafe()
  292. {
  293.     uint8_t relayStatus;
  294.     uint32_t boardTemperature = 0, timeStamp = 0;
  295.  
  296.     /* Turn of servo current feed */
  297.     PORTC &= ~(1<<PC0);
  298.  
  299.  
  300.     while(1){
  301.         /* check if any messages have been received */
  302.         while(msg_received) {
  303.             /* This relay is adressed*/
  304.             if(rxMsg.Data.bytes[0] == BLINDS_CMD_RESET ){
  305.                 /* Return from failsafe mode */
  306.                 return;
  307.             }
  308.         }
  309.  
  310.         if( bios->timebase_get() - timeStamp >= FAILSAFE_SEND_PERIOD ){
  311.             timeStamp = bios->timebase_get();
  312.             /* Send relay status to CAN */
  313.             boardTemperature = getTC1047temperature();
  314.  
  315.             txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  316.             txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  317.             txMsg.Data.bytes[2] = FAILSAFE_MODE;
  318. #if NUMBER_OF_RCS >0
  319.             txMsg.Data.bytes[3] = getPosition(1);
  320. #endif
  321. #if NUMBER_OF_RCS >1
  322.             txMsg.Data.bytes[4] = getPosition(2);
  323. #endif
  324. #if NUMBER_OF_RCS >2
  325.             txMsg.Data.bytes[5] = getPosition(3);
  326. #endif
  327.             txMsg.DataLength = NUMBER_OF_RCS+3;
  328.  
  329.             bios->can_send(&txMsg);
  330.         }
  331.     }
  332. }
  333.  
  334.