
// Global variables
int8 RomBytes[8];      
int8 lastDiscrep = 0; 
short doneFlag = 0; 
int8 FoundROM[9][8];    // Table of found ROM codes, 8 bytes for each 
int8 numROMs; 
int8 dowcrc;            // crc is accumulated in this variable 


//calc_CRC - INTERNAL FUNCTION 
//Purpose:    To calculate an 8-bit CRC based on a polynomial and the series 
//            of data bytes 
//Note:       Polynomial used x^8 + x^5 + x^4 + 1 = 10001100 
//Inputs:     A pointer to an array of the data bytes and an int saying how many 
//            bytes there are in the data array 
//Outputs:    An int8 which is the calculated CRC 
int8 calc_CRC(int8* data, int8 bytes) 
{ 
   #define CRC_POLY      0x8C 
   int8 shift_register = 0, i, datab, bits; 

   for(i = 0; i < bytes; ++i) 
   { 
      datab = *(data + i); 

      for(bits = 0; bits < 8; ++bits) 
      { 
         if(bit_test((shift_register ^ datab), 0)) 
         { 
            shift_register = shift_register >> 1; 
            shift_register ^= CRC_POLY; 
         } 
         else 
         { 
            shift_register = shift_register >> 1; 
         } 

         datab = datab >> 1; 
      } 
   } 
   return shift_register; 
} //calc_CRC 


// Returns 0 for one wire device presence, 1 for none 
int8 ow_reset(void) 
{ 
   int8 presence; 
    
   output_low(DQ);
   delay_us(488);          // Min. 480uS 
   output_float(DQ); 
   delay_us(72);           // Takes 15 to 60uS for devices to respond 
   presence = input(DQ); 
   delay_us(424);          // Wait for end of timeslot 
   return(presence); 
} 

//****************************************************************************** 
// Read bit on one wire bus 
int8 read_bit(void) 
{ 
   output_low(DQ); 
   delay_us(1);         // Added, 1uS min. Code relied on 8051 being slow. 
   output_float(DQ); 
   delay_us(12);        // Read within 15uS from start of time slot 
   return(input(DQ));    
}    

//****************************************************************************** 
void write_bit(int8 bitval) 
{ 
   output_low(DQ); 

   if(bitval == 1) { 
      delay_us(1);      // 1uS min. Code relied on 8051 being slow. 
      output_float(DQ); 
   } 
   delay_us(105);       // Wait for end of timeslot 
   output_float(DQ); 
} 

//****************************************************************************** 
int8 read_byte(void) 
{ 
   int8 i; 
   int8 val = 0; 

   for(i=0;i<8;i++) 
   { 
      if(read_bit()) val |= (0x01 << i); 
      delay_us(120);  // To finish time slot 
   } 

   return val; 
} 

//****************************************************************************** 
void write_byte(int8 val) 
{ 
   int8 i; 
   int8 temp; 

   for (i=0;i<8;i++) 
   { 
      temp = val >> i; 
      temp &= 0x01; 
      write_bit(temp); 
   } 

   delay_us(105); 
} 

//****************************************************************************** 
// One wire crc 
int8 ow_crc(int8 x) 
{ 
   dowcrc = calc_CRC(x,8); 
   return dowcrc; 
} 

//****************************************************************************** 
// Searches for the next device on the one wire bus. If there are no more 
// devices on the bus then false is returned. 
int8 Next(void) 
{ 
   int8 m = 1;             // ROM Bit index 
   int8 n = 0;             // ROM Byte index 
   int8 k = 1;             // Bit mask 
   int8 x = 0; 
   int8 discrepMarker = 0; 
   int8 g;                 // Output bit 
   int8 nxt;               // Return value 
   short flag; 

   nxt = FALSE;            // Reset next flag to false 
   dowcrc = 0;             // Reset the dowcrc 
   flag = ow_reset(); 

   if (flag||doneFlag)     // If no parts return false 
   { 
      lastDiscrep = 0;     // Reset the search 
      return FALSE; 
   } 
    
   write_byte(0xF0);       // Send SearchROM command 
   do 
   { 
      x = 0; 
      if (read_bit() == 1) 
         x = 2; 
      delay_us(120); 
      if (read_bit() == 1) 
         x |= 1;                    // And it's complement  
      if (x == 3)                   // There are no devices on the one wire bus 
         break; 
      else 
      { 
         if (x > 0)                 // All devices coupled have 0 or 1 
            g = x >> 1;             // Bit write value for search 

         // If this discrepancy is before the last discrepancy on a previous 
         // Next then pick the same as last time. 
         else 
         { 
            if (m < lastDiscrep) 
               g = ((RomBytes[n] & k) > 0); 
            // If equal to last pick 1 
            else 
               g = (m == lastDiscrep);  // If not then pick 0 

               // If 0 was picked then record position with mask k 
               if (g == 0) discrepMarker = m; 
         } 

         // Isolate bit in ROM[n] with mask k 
         if (g == 1) RomBytes[n] |= k; 
         else RomBytes[n] &= ~k; 

         write_bit(g);  // ROM search write 

         m++;           // Increment bit counter m 
         k = k << 1;    // and shift the bit mask k 
         // If the mask is 0 then go to new ROM 
         if (k == 0) 
         {  // Byte n and reset mask 
            ow_crc(RomBytes[n]);      // Accumulate the crc 
            n++; 
            k++; 
         } 
      } 
   } while (n < 8);  // Loop through until through all ROM bytes 0-7 

   if (m < (65||dowcrc))   // If search was unsuccessful then 
      lastDiscrep = 0;     // reset the last Discrepancy to zero 
   else  // Search was successful, so set lastDiscrep, lastOne, nxt 
   { 
      lastDiscrep = discrepMarker; 
      doneFlag = (lastDiscrep == 0); 
      nxt = TRUE; // Indicates search not yet complete, more parts remain 
   } 

   return nxt; 
} 

//****************************************************************************** 
// Resets current state of a ROM search and calls Next to find the first device 
// on the one wire bus. 
int8 First(void) 
{ 
   lastDiscrep = 0; 
   doneFlag = FALSE; 
   return Next();    // Call Next and return it's return value; 
} 

//****************************************************************************** 
int8 FindDevices(void) 
{ 
   int8 m, cont = 0; 
   if(!ow_reset()) 
   { 
      if(First())    // Begins when at least one part found 
      { 
         numROMs = 0; 
         do 
         { 
            numROMs++;  
            cont++; 
            for (m=0;m<8;m++) 
            { 
               FoundROM[numROMs][m] = RomBytes[m]; 
            } 
         } while (Next());   // Continues until no additional                              
      } 
   } 
   return cont; 

} 

//****************************************************************************** 
// Sends Match ROM command to bus then device address 
int8 Send_MatchRom(void) 
{ 
   int8 i; 
   if (ow_reset()) return FALSE;          // 0 if device present 
   write_byte(0x55);                      // Match ROM 

   for (i=0;i<8;i++) 
   { 
      write_byte(FoundRom[numROMs][i]);   // Send ROM code 
   } 

   return TRUE; 
}
