Advertisement
Guest User

Weather Station from Practical Arduino

a guest
Nov 23rd, 2013
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.03 KB | None | 0 0
  1. /**
  2.  * WeatherStationReceiver
  3.  *
  4.  * Receives and decodes a pulse-width and transition encoded RF
  5.  * bitstream, received through a 433MHz receiver module into the PB0
  6.  * Input Capture Pin (ICP).
  7.  *
  8.  * The transmitter is from the La Crosse WS-2355 Weather Station
  9.  * package, the RF transmitter is the integrated thermo/hygro station,
  10.  * (part number WS-2300-25S), and cable connections between the rain and
  11.  * wind sensors are made to the WS-2300-25S unit as it is the central RF
  12.  * transmitter. The cable connected rainfall sensor is part number
  13.  * WS-2300-16. The cable connected wind speed and direction sensor is
  14.  * part number TX20.
  15.  *
  16.  * Copyright 2009 Marc Alexander <marc.alexander@gmail.com>
  17.  * Copyright 2009 Jonathan Oxer <jon@oxer.com.au>
  18.  * http://www.practicalarduino.com/projects/weather-station-receiver
  19.  */
  20.  
  21. /**
  22.  * NOTE:
  23.  * The rainfall count may be 11 bits, not 12 bits. Once I saw a 4000+
  24.  * reading on it that was not generated by rainfall pulses, so a higher
  25.  * bit there may mean something else? Still investigating.
  26.  */
  27.  
  28. /**
  29.  * TODO:
  30.  * 1.   Add: WSR_RESET() call from a dead-time timeout. If no RF
  31.  * activity is received within a few mS, reset the receiver state
  32.  * machine. Currently unsquelched RF noise is resetting it anyway
  33.  * given the receiver model used, but a quiet receiver timeout should be
  34.  * there also. Make sure boundary condition of reset just as new bit /
  35.  * period coming in is not a problem causing loss of packet start if
  36.  * reset happens during first transition/bit in.
  37.  */
  38.  
  39. /*--------------------------------------------------------------------------------------
  40.   Includes
  41. --------------------------------------------------------------------------------------*/
  42. #include "WeatherStationReceiver.h"
  43.  
  44. /*--------------------------------------------------------------------------------------
  45.   Variables
  46. --------------------------------------------------------------------------------------*/
  47. //----------
  48. // Timer 1 Input capture period and captured event time detection
  49. uint uiICP_CapturedTime;
  50. uint uiICP_PreviousCapturedTime;
  51. uint uiICP_CapturedPeriod;
  52. uint uiICP_PreviousCapturedPeriod;
  53. byte bICP_CapturedPeriodWasHigh;
  54. byte bICP_PreviousCapturedPeriodWasHigh;
  55. unsigned long ulICP_Timestamp_262_144mS;
  56. //----------
  57. byte bICP_WSR_State;                                 //Interpreter state machine
  58. byte bICP_WSR_PacketData[WSR_PACKETARRAYSIZE][4+8];  //incoming RF packet data with 4 byte timestamp at start, already bit reversed to suit.
  59.                                                      //main array size must be ^2, and there may be some other count dependencies in the interpreter.
  60. byte bICP_WSR_PacketInputPointer;           //
  61. byte bICP_WSR_PacketOutputPointer;          //
  62. byte bICP_WSR_PacketInputBitPointer;        //
  63. uint uiICP_WSR_ReceivedPacketCount;         //
  64. //----------
  65. // Saved timestamp at packet receive conversion
  66. unsigned long ulWSR_LastTimestamp_262_144mS;
  67. //----------
  68. // Real world data, latest received and converted by Packet_Converter_WS2355()
  69. byte bWSR_StationTransmitterID;         //
  70. sint siWSR_CurrentTemperature;          //
  71. byte bWSR_CurrentHumidity;              //
  72. byte bWSR_CurrentWindDirection;         //
  73. uint uiWSR_CurrentWindSpeed_m_per_sec;  //
  74. uint uiWSR_RainfallCount;               //
  75. unsigned long ulWSR_Rainfall_mm_x10;
  76. //----------
  77. const char strWindDirection[16][4] =
  78. {
  79.   "N  ", "NNE", "NE ", "ENE",
  80.   "E  ", "ESE", "SE ", "SSE",
  81.   "S  ", "SSW", "SW ", "WSW",
  82.   "W  ", "WNW", "NW ", "NNW"
  83. };
  84.  
  85. // Comment out for a normal build
  86. // Uncomment for a debug build
  87. #define DEBUG
  88.  
  89. /**
  90.  * Initial configuration
  91.  */
  92. void setup(void)
  93. {
  94.   Serial.begin( 38400 );   //using the serial port at 38400bps for debugging and logging
  95.   Serial.println( "Weather Station Receiver has powered up" );
  96.  
  97.   Init_Ports();
  98.   Init_RF_Interpreters();
  99.   interrupts();   // Enable interrupts (NOTE: is this necessary? Should be enabled by default)
  100. }
  101.  
  102. /**
  103.  * Main program loop
  104.  */
  105. void loop(void)
  106. {
  107.   Packet_Converter_WS2355();
  108. }
  109.  
  110. /**
  111.  * Initialise port initial state and data direction registers
  112.  */
  113. void Init_Ports()
  114. {
  115.   DDRB = 0x2F;   // B00101111
  116.   Serial.println("Ports initialised.");
  117. }
  118.  
  119. /*--------------------------------------------------------------------------------------
  120.    Packet_Converter_WS2355
  121.    Inspect, validate and convert any fresh incoming packet data to the latest real world values
  122.       bit      1         2         3         4         5   byte                 1
  123. <-TS  1234567890123456789012345678901234567890123456789012 00112233 4455667788990
  124.       /--||--\/--||--\/--||--\/--||--\/--||--\/--||--\/--|
  125.    1) 0000100101000010001001111000010100110011101011000001 00000043 0942278533AC1 st:34 ok: 23.3? (533 = 53.3deg, - 30.0deg offset)
  126.                 ssiiiiiiii                                                  ttt
  127.    2) 0000100100010010001001111000010100001101101011111000 00000045 091227850DAF8 st:34 ok: 50% RH
  128.                 ssiiiiiiii                                                 hh
  129.    3) 0000100100100010001001111000000010001100111101111000 00000046 092227808CF78 st:34 ok: 140 rainfall, 72.5 mm
  130.                 ssiiiiiiii        rrrrrrrrrrrr
  131.    4) 0000100101110010001001111000000000001100111111111101 00000047 097227800CFFD st:34 ok: W   (12) wind, speed 0.0m/s 0.0km/h
  132.                 ssiiiiiiii
  133.    5) 0000100101000010001001111000010100110011101011000001 00000049 0942278533AC1 st:34 ok: 23.3?
  134.                 ssiiiiiiii
  135.    6) 0000100100010010001001111000010100001101101011111000 0000004A 091227850DAF8 st:34 ok: 50% RH
  136.                 ssiiiiiiii
  137.    7) 0000100100100010001001111000000010001100111101111000 0000004B 092227808CF78 st:34 ok: 140 rainfall, 72.5 mm
  138.                 ssiiiiiiii
  139.    8) 0000100101110010001001111000000000001100111111111101 0000004D 097227800CFFD st:34 ok: W   (12) wind, speed 0.0m/s 0.0km/h
  140.                 ssiiiiiiii                wwww        cccc
  141.  
  142.    cccc = sum of all previous nibbles, from the start of the packet (all 48 preceding bits, 12 nibbles)
  143.  
  144.    ss   = sensor/packet identifier
  145.  
  146.    wwww = wind direction
  147.              0 = N   1 = NNE   2 = NE    3 = ENE
  148.              4 = E   5 = ESE   6 = SE    7 = SSE
  149.              8 = S   9 = SSW  10 = SW   11 = WSW
  150.             12 = W  13 = WNW  14 = NW   15 = NNW
  151.  
  152.    iiiiiiii = station ID byte. May not be using the top(left) bit of this byte, but is using bits 0-6 at least.
  153.               Every time the WS-2300-25S transmitter batteries are changed, it generates a new semi-random
  154.               station ID. The user is expected to power cycle the WS-2355 receiver which will then
  155.               'lock on' to the next received station ID.
  156.  
  157.    rrrrrrrrrrrr = 12 (potential?) bits of rainfall count.
  158.                Note that it is up to the data analyser and any time window formatting
  159.                to treat this as a differential value only. It is expected that the value will
  160.                overflow in long term use.
  161.  
  162.    For more data decoding and locations, see conversion code below
  163.  
  164. --------------------------------------------------------------------------------------*/
  165. void Packet_Converter_WS2355(void)
  166. {
  167.   byte b;
  168.   byte c;
  169.   sint si;
  170.  
  171.   if( bICP_WSR_PacketInputPointer != bICP_WSR_PacketOutputPointer )
  172.   {
  173.     Serial.println("Packet Input Pointer different.");
  174.     // A fresh packet is ready to check and convert
  175.     #ifdef DEBUG
  176.     if( (ulICP_Timestamp_262_144mS - ulWSR_LastTimestamp_262_144mS) > 8 )
  177.     {
  178.       // Blank separator line if there has been more than about 2 seconds since the last
  179.       // packet to make it easier to see what belongs with what
  180.       Serial.println("!");
  181.     }
  182.     else {
  183.       Serial.print(".");
  184.     }
  185.     #endif
  186.  
  187.     #ifdef DEBUG
  188.     //print it in binary text out the serial port
  189.     Serial.print("BINARY=");
  190.     for( b = WSR_TIMESTAMP_BIT_OFFSET ; b < (WSR_RFPACKETBITSIZE+WSR_TIMESTAMP_BIT_OFFSET) ; b++ )
  191.     {
  192.       if( (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][b >> 3] & (0x80 >> (b&0x07))) != 0 )
  193.       {
  194.         //Serial.print( '1', BYTE );
  195.         Serial.write("1");
  196.       } else {
  197.         //Serial.print( '0', BYTE );
  198.         Serial.write("0");
  199.       }
  200.       if( b == 31 )
  201.         //Serial.print( ' ', BYTE );   //timestamp seperator
  202.         Serial.write("-");
  203.     }
  204.     Serial.println();
  205.  
  206.     //print it in hex text out the serial port
  207.     //Serial.print( ' ', BYTE );
  208.     Serial.print("HEX=");
  209.     for( b = 0 ; b < ((WSR_RFPACKETBITSIZE+WSR_TIMESTAMP_BIT_OFFSET)/4) ; b += 2 )
  210.     {
  211.       // One nibble at a time
  212.       c = bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][b >> 1];
  213.       // Top nibble
  214.       Serial.print( (c & 0xF0) >> 4, HEX );
  215.       // Bottom nibble, drop the last one since it's not part of the 52 incoming bits
  216.       if( b < (((WSR_RFPACKETBITSIZE+WSR_TIMESTAMP_BIT_OFFSET)/4)-1) )
  217.       Serial.print( (c & 0x0F), HEX );
  218.       // Timestamp seperator
  219.       if( b == 6 )
  220.         //Serial.print( ' ', BYTE );
  221.         Serial.write("#");
  222.     }
  223.     Serial.println();
  224.     #endif
  225.  
  226.     //----------------------------------------------------------------------------
  227.     if( PacketAndChecksum_OK_WS2355 )
  228.     {
  229.       // Extract the station ID
  230.       b  = (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][5] << 4);
  231.       b += (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][6] >> 4);
  232.       bWSR_StationTransmitterID = b;
  233.       // Print to serial port
  234.       Serial.print( "STATIONID=" );
  235.       Serial.println( bWSR_StationTransmitterID, DEC );
  236.  
  237.       // Bits 4 and 5 of this byte are the sensor/packet ID
  238.       b = bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][5];
  239.       b = (b >> 4) & 0x03;
  240.       switch( b )
  241.       {
  242.         case 0:
  243.         {
  244.           // 0: temperature
  245.           // Sensor/packet ID bits are 0x00, temperature is present in this packet
  246.           // Lower nibble of byte 7 is first temperature digit, take care of 3xx offset
  247.           si  = ((bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][7] & 0x0F) * 100);
  248.           si += ((bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8] >> 4) * 10);
  249.           si +=  (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8] & 0x0F);
  250.           siWSR_CurrentTemperature = (si - 300);
  251.  
  252.           // Print to serial port with decimal place management
  253.           Serial.print("TEMPERATURE=");
  254.           Serial.print( (siWSR_CurrentTemperature/10), DEC );
  255.           //Serial.print( '.', BYTE );
  256.           Serial.write(".");
  257.           if( siWSR_CurrentTemperature < 0 ) {
  258.             Serial.println( ((0-siWSR_CurrentTemperature)%10), DEC );
  259.           } else {
  260.             Serial.println( (siWSR_CurrentTemperature%10), DEC );
  261.           }
  262.           break;
  263.         }
  264.         case 1:
  265.         {
  266.           // 1: humidity
  267.           //sensor/packet ID bits are 0x01, humidity is present in this packet
  268.           c  = ((bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][7] & 0x0F) * 10);
  269.           c +=  (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8] >> 4);
  270.           bWSR_CurrentHumidity = c;
  271.  
  272.           // Print to serial port with decimal place management
  273.           Serial.print("HUMIDITY=");
  274.           Serial.println( bWSR_CurrentHumidity, DEC );
  275.           break;
  276.         }
  277.         case 2:
  278.         {
  279.           // 2: rainfall
  280.           si  = (sint)(bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][7] & 0x0F) << 8;
  281.           si +=        bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8];
  282.           uiWSR_RainfallCount = (uint)si;
  283.  
  284.           // Killer (for the Arduino) long multiply here, put in for now to demo real mm of rainfall maths
  285.           ulWSR_Rainfall_mm_x10 = (((unsigned long)uiWSR_RainfallCount * 518) / 100);
  286.  
  287.           // Print to serial port
  288.           Serial.print("RAINFALL=");
  289.           Serial.print( (ulWSR_Rainfall_mm_x10/10), DEC );
  290.           //Serial.print( '.', BYTE );
  291.           Serial.write(".");
  292.           Serial.println( (ulWSR_Rainfall_mm_x10%10), DEC );
  293.           break;
  294.         }
  295.         case 3:
  296.         {
  297.           // 3: wind direction and speed
  298.           // Sensor/packet ID bits are 0x03, wind data is present in this packet
  299.           // Wind direction
  300.           bWSR_CurrentWindDirection = (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8] & 0x0F);
  301.  
  302.           //wind speed, decimal value is metres per second * 10 (1 fixed deciml place)
  303.           si  = (sint)(bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][7] & 0x10) << 4;
  304.           si +=      ((bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][7] & 0x0F) << 4);
  305.           si +=       (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][8] >> 4);
  306.           uiWSR_CurrentWindSpeed_m_per_sec = (uint)si;
  307.  
  308.           // Print to serial port with decimal place management
  309.           Serial.print("WINDDIRECTION=");
  310.           Serial.println( strWindDirection[bWSR_CurrentWindDirection] );
  311.  
  312.           Serial.print("WINDSPEED=");
  313.           Serial.print( (uiWSR_CurrentWindSpeed_m_per_sec/10), DEC );
  314.           //Serial.print( '.', BYTE );
  315.           Serial.write(".");
  316.           Serial.println( (uiWSR_CurrentWindSpeed_m_per_sec%10), DEC );
  317.           break;
  318.         }
  319.         default:
  320.         {
  321.           break;
  322.         }
  323.       }
  324.     } else {
  325.       Serial.print( " bad checksum or packet header" );
  326.     }
  327.  
  328.     //----------------------------------------------------------------------------
  329.     //save the last timestamp value, currently used for extra CR/LF in serial print
  330.     ulWSR_LastTimestamp_262_144mS = ulICP_Timestamp_262_144mS;
  331.     //----------------------------------------------------------------------------
  332.     //conversion process done on this packet, move the output pointer along
  333.     bICP_WSR_PacketOutputPointer = ((bICP_WSR_PacketOutputPointer+1)&(WSR_PACKETARRAYSIZE-1));
  334.   }
  335. }
  336.  
  337.  
  338. /**
  339.  * PacketAndChecksum_OK_WS2355
  340.  * Return true if packet checksum and inspection is ok
  341.  */
  342. byte PacketAndChecksum_OK_WS2355(void)
  343. {
  344.   byte dataPos;
  345.   byte checksum;
  346.  
  347.   // First check, last 4 bits of packet are sum of the previous 48 bits (12 nibbles)
  348.   // Don't forget to offset past the timestamp in the first 4 bytes
  349.   checksum = 0;
  350.   for( dataPos = 4; dataPos < 10; dataPos++ )
  351.   {
  352.     // Checked a byte at a time, accumulate into checksum
  353.     checksum += (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][dataPos] >> 4);
  354.     checksum += (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][dataPos] & 0x0F);
  355.   }
  356.   checksum &= 0x0F;
  357.   if( checksum != (bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][10] >> 4) )
  358.   {
  359.     return( false );   // Checksum does not match
  360.   }
  361.  
  362.   // Second check, first byte of packet must be 0x09 ( B00001001 ), appears to be
  363.   // the main identifier for this station
  364.   if( bICP_WSR_PacketData[bICP_WSR_PacketOutputPointer][4] != 0x09 )
  365.   {
  366.     return( false );
  367.   }
  368.  
  369.   return( true );
  370. }
  371.  
  372.  
  373. /**
  374.  * Init_RF_Interpreters
  375.  */
  376. void Init_RF_Interpreters(void)
  377. {
  378.   //Call macros that reset any RF_Interpreter_... state machine and housekeeping values
  379.   WSR_RESET();
  380.  
  381.   //RF decode ports setup
  382.   //Marc making PB0 (ICP1 Input Capture) a floating input for RX ASK bitstream receiving
  383.   //PB0 was used by the Color LCD/Joystick Shield for the backlight_on signal,
  384.   //R2 has now been removed on the lcd pcb, and Q1 C-E shorted to keep the BL always on
  385.   DDRB  &= ~(1<<DDB0);    //PBO(ICP1) input
  386.   PORTB &= ~(1<<PORTB0);  //ensure pullup resistor is also disabled
  387.  
  388.   //PORTD6 and PORTD7, GREEN and RED test LED setup
  389.   DDRD  |=  B11000000;      //(1<<PORTD6);   //DDRD  |=  (1<<PORTD7); (example of B prefix)
  390.   GREEN_TESTLED_OFF();      //GREEN test led off
  391.   RED_TESTLED_ON();         //RED test led on
  392.   //PORTD |=  _BV(PORTD6);    //GREEN test led off  (example of _BV macro)
  393.   //PORTD &= ~_BV(PORTD7);    //RED test led on     (example of _BV macro)
  394.   //PORTD |=  (1<<PORTD6);    //GREEN test led off  (example of AVR studio style)
  395.   //PORTD &= ~(1<<PORTD7);    //RED test led on     (example of AVR studio style)
  396.  
  397.   //---------------------------------------------------------------------------------------------
  398.   //ICNC1: Input Capture Noise Canceler         On, 4 successive equal ICP1 samples required for trigger (4*4uS = 16uS delayed)
  399.   //ICES1: Input Capture Edge Select            1 = rising edge to begin with, input capture will change as required
  400.   //CS12,CS11,CS10   TCNT1 Prescaler set to 0,1,1 see table and notes above
  401.   TCCR1A = B00000000;   //Normal mode of operation, TOP = 0xFFFF, TOV1 Flag Set on MAX
  402.                         //This is supposed to come out of reset as 0x00, but something changed it, I had to zero it again here to make the TOP truly 0xFFFF
  403.   TCCR1B = ( _BV(ICNC1) | _BV(CS11) | _BV(CS10) );
  404.   SET_INPUT_CAPTURE_RISING_EDGE();
  405.   //Timer1 Input Capture Interrupt Enable, Overflow Interrupt Enable  
  406.   TIMSK1 = ( _BV(ICIE1) | _BV(TOIE1) );
  407.   Serial.println("RF Interpreters initialised.");
  408. }
  409.  
  410. /*--------------------------------------------------------------------------------------
  411.   TIMER1_OVF_vect
  412.   Timer1 overflow interrupt routine
  413.   262.144 mS TOF period
  414.   If used to feed a 32 bit timestamp counter, (0xFFFFFFFF = 4294967295 count before overlow)
  415.   = 1125899906 seconds = 18764998 minutes = 312749 = 13031 days = 35 years.
  416. --------------------------------------------------------------------------------------*/
  417. ISR( TIMER1_OVF_vect )
  418. {
  419.   //increment the 32 bit timestamp counter (see overflow notes above)
  420.   //overflow is allowed as this timestamp is most likely to be used as a delta from the previous timestamp,
  421.   //so if it's used externally in the same 32 bit unsigned type it will come out ok.
  422.   ulICP_Timestamp_262_144mS++;
  423. }
  424.  
  425. /*--------------------------------------------------------------------------------------
  426.   TIMER1_CAPT_vect
  427.   Timer1 input capture interrupt routine
  428. --------------------------------------------------------------------------------------*/
  429. ISR( TIMER1_CAPT_vect )
  430. {
  431.   // Immediately grab the current capture time in case it triggers again and
  432.   // overwrites ICR1 with an unexpected new value
  433.   uiICP_CapturedTime = ICR1;
  434.  
  435.   // GREEN test led on (flicker for debug)
  436.   GREEN_TESTLED_ON();
  437.  
  438.   //----------------------------------------------------------------------------
  439.   //immediately grab the current capture polarity and reverse it to catch all the subsequent high and low periods coming in
  440.   //If the initial period filter passes below, this will be inspected to become bICP_EventPolarity
  441.   if( INPUT_CAPTURE_IS_RISING_EDGE() )
  442.   {
  443.     SET_INPUT_CAPTURE_FALLING_EDGE();      //previous period was low and just transitioned high
  444.     bICP_CapturedPeriodWasHigh = false;    //uiICP_CapturedPeriod about to be stored will be a low period      
  445.   } else {
  446.     SET_INPUT_CAPTURE_RISING_EDGE();       //previous period was high and transitioned low
  447.     bICP_CapturedPeriodWasHigh = true;     //uiICP_CapturedPeriod about to be stored will be a high period      
  448.   }
  449.  
  450.   //----------------------------------------------------------------------------
  451.   //calculate the current period just measured, to accompany the polarity now stored
  452.   uiICP_CapturedPeriod = (uiICP_CapturedTime - uiICP_PreviousCapturedTime);
  453.  
  454.   //----------------------------------------------------------------------------
  455.   // RF Pulse filtering, width test and polarity are analysed now, call the
  456.   // interpreter(s) to analyse them
  457.   RF_Interpreter_WS2355( /*uiICP_CapturedPeriod, bICP_CapturedPeriodWasHigh*/);   //arguments removed and made global
  458.  
  459.  
  460.   //----------------------------------------------------------------------------
  461.   //save the current capture data as previous so it can be used for period calculation again next time around
  462.   uiICP_PreviousCapturedTime           = uiICP_CapturedTime;
  463.   uiICP_PreviousCapturedPeriod         = uiICP_CapturedPeriod;
  464.   bICP_PreviousCapturedPeriodWasHigh   = bICP_CapturedPeriodWasHigh;
  465.  
  466.   //GREEN test led off (flicker for debug)
  467.   GREEN_TESTLED_OFF();
  468. }
  469.  
  470. /*--------------------------------------------------------------------------------------
  471.   RF_Interpreter_WS2355
  472.  
  473.   The WS2355 sends 52 bits in a packet and the format is
  474.   A  long high followed by a long low is 0
  475.   A short high followed by a long low is 1
  476.  
  477.   Not much more is done in this input capture interrupt routine apart from the
  478.   00001 leader check and then loading of the full 52 bit packet.
  479.  
  480.   bICP_WSR_PacketInputPointer will be moved along when received, the main loop
  481.   called Packet_Converter_WS2355() routine will do the rest of the work
  482.   to check and convert each packet's data content.
  483. --------------------------------------------------------------------------------------*/
  484. void RF_Interpreter_WS2355( /*uiICP_CapturedPeriod, bICP_CapturedPeriodWasHigh*/ )
  485. {
  486.   volatile byte b;
  487.   byte bValidBit = false;   // 0=false(WSR_BIT_NONE), 1=WSR_BIT_ZERO, 2=WSR_BIT_ONE
  488.  
  489.   //#warning A quiet-time timeout must be added to this interepreter, to reset the state machine any time there is a long quiet break in rx
  490.  
  491.   //discard the captured period if it is out of the expected range, it is noise...
  492.   if( (uiICP_CapturedPeriod >= WSR_PERIOD_FILTER_MIN) && (uiICP_CapturedPeriod <= WSR_PERIOD_FILTER_MAX) )
  493.   {
  494.     //----------------------------------------------------------------------------
  495.     //PERIOD INITIAL DURATION FILTER OK, CONTINUE
  496.     //----------------------------------------------------------------------------
  497.     //Check if this is a valid zero(long high) or one(short high) bit, or low period in between
  498.     if( bICP_CapturedPeriodWasHigh )
  499.     {
  500.       //got a high period, could be a valid bit
  501.       if( (uiICP_CapturedPeriod >= WSR_SHORT_PERIOD_MIN) && (uiICP_CapturedPeriod <= WSR_SHORT_PERIOD_MAX) )
  502.       {
  503.         //short high, valid one bit
  504.         bValidBit = WSR_BIT_ONE;
  505.       } else if( (uiICP_CapturedPeriod >= WSR_LONG_PERIOD_MIN) && (uiICP_CapturedPeriod <= WSR_LONG_PERIOD_MAX) ) {
  506.         //long high, valid zero bit
  507.         bValidBit = WSR_BIT_ZERO;
  508.       } else {
  509.         //invalid high period, in the dead zone between short and long bit period lengths
  510.         WSR_RESET();
  511.       }
  512.     }
  513.     //else
  514.     //{
  515.     //   //got a low period, ignored
  516.     //}
  517.     //----------------------------------------------------------------------------
  518.     //Enter the state machine to load and prepare the incoming packet to bICP_WSR_PacketData[8][4+8]
  519.     if( bValidBit != false )
  520.     {
  521.       switch( bICP_WSR_State )
  522.       {
  523.         case WSR_STATE_IDLE:
  524.         {
  525.           if( bValidBit == WSR_BIT_ZERO )
  526.           {
  527.             //first bit of valid packet is zero (4 zero's, maybe 3)
  528.             //zero out the appropriate bit on the current input packet
  529.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][bICP_WSR_PacketInputBitPointer >> 3]
  530.                &= ~(0x01 << (bICP_WSR_PacketInputBitPointer&0x07));
  531.             bICP_WSR_PacketInputBitPointer++;
  532.             bICP_WSR_State = WSR_STATE_LOADING_BITSTREAM;
  533.           } else {
  534.             WSR_RESET();
  535.           }
  536.           break;
  537.         }
  538.         case WSR_STATE_LOADING_BITSTREAM:
  539.         {
  540.           // Potentially valid packet bitstream is on its way in, keep loading it up
  541.           if( bValidBit == WSR_BIT_ZERO )
  542.           {
  543.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][bICP_WSR_PacketInputBitPointer >> 3]
  544.                &= ~(0x80 >> (bICP_WSR_PacketInputBitPointer&0x07));
  545.           } else {
  546.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][bICP_WSR_PacketInputBitPointer >> 3]
  547.                |=  (0x80 >> (bICP_WSR_PacketInputBitPointer&0x07));
  548.           }
  549.  
  550.           // Check at appropriate location of the incoming bitstream, if it is valid and throw away if not
  551.           if( bICP_WSR_PacketInputBitPointer == (WSR_TIMESTAMP_BIT_OFFSET + 4) )
  552.           {
  553.             //                               01234    01234
  554.             // Acceptable start to packet is 00001 or 00010 (lost the first 0), could optimise
  555.             // this but will leave with b for now for stability and debugging
  556.             b = bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][4/*bICP_WSR_PacketInputBitPointer >> 3*/];
  557.             b &= B11111000;
  558.             if( b == B00010000 )
  559.             {
  560.               //valid packet 00010 start (with lost first zero), realign and continue
  561.               bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][4/*bICP_WSR_PacketInputBitPointer >> 3*/] = B00001000;
  562.               bICP_WSR_PacketInputBitPointer++;      //move up one past the inserted missing bit
  563.             } else if( b != B00001000 ) {
  564.               //invalid packet start, not 00001, reset
  565.               WSR_RESET();
  566.             }
  567.           }
  568.  
  569.           // Final check, has the last packet bit (52 bits total) come in? If so, mark this packet
  570.           // as done and move the major packet input pointer along
  571.           if( bICP_WSR_PacketInputBitPointer == (WSR_TIMESTAMP_BIT_OFFSET + (WSR_RFPACKETBITSIZE-1)) )
  572.           {
  573.             // Got full packet, timestamp it for the main loop
  574.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][0] = byte(ulICP_Timestamp_262_144mS >> 24);
  575.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][1] = byte(ulICP_Timestamp_262_144mS >> 16);
  576.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][2] = byte(ulICP_Timestamp_262_144mS >>  8);
  577.             bICP_WSR_PacketData[bICP_WSR_PacketInputPointer][3] = byte(ulICP_Timestamp_262_144mS);
  578.             // Pointer and packet count
  579.             bICP_WSR_PacketInputPointer = ((bICP_WSR_PacketInputPointer+1)&(WSR_PACKETARRAYSIZE-1));//only the lower three bits are used for the 8 entry array
  580.             uiICP_WSR_ReceivedPacketCount++;                                                        //note will overflow and wrap, used for display of progress only
  581.             WSR_RESET();
  582.           }
  583.  
  584.           // Increment pointer to next new bit location
  585.           bICP_WSR_PacketInputBitPointer++;
  586.           break;
  587.         }
  588.       }
  589.     }
  590.     //----------------------------------------------------------------------------
  591.   } else {
  592.     //----------------------------------------------------------------------------
  593.     // PERIOD OUT OF BOUNDS, DISCARD
  594.     // This will throw away any out of range periods and reset the state machine, high or low.
  595.     //----------------------------------------------------------------------------
  596.     WSR_RESET();
  597.   }
  598. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement