title: Embedded C code review
body: <p>I am required to write a function that uses a look up table for ADC values for temperature sensor analog input, and it finds out the temperature given an ADC value by "interpolating" - linear approximation.
  I have created a function and written some test cases for it, I want to know if there is something which you guys can suggest to improve the code, since this is supposed to be for an embedded uC, probably stm32.</p>
  
  <p>I am posting my code and attaching my C file, it will compile and run.</p>
  
  <p>Please let me know if you have any comments/suggestions for improvement.</p>
  
  <p>I also want to know a bit about the casting from uint32_t to float that I am doing, if it is efficient way to code.    </p>
  
  <pre><code>#include &lt;windows.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;stdint.h&gt;
  
  #define TEMP_ADC_TABLE_SIZE 15
  
  typedef struct
  {
   int8_t temp;     
   uint16_t ADC;       
  }Temp_ADC_t;
  
  const Temp_ADC_t temp_ADC[TEMP_ADC_TABLE_SIZE] = 
  {
      {-40,880}, {-30,750},
      {-20,680}, {-10,595},
      {0,500}, {10,450},
      {20,410}, {30,396},
      {40,390}, {50,386},
      {60,375}, {70,360},
      {80,340}, {90,325},
      {100,310}
  };
  
  // This function finds the indices between which the input reading lies.
  // It uses an algorithm that doesn't need to loop through all the values in the 
  // table but instead it keeps dividing the table in two half until it finds
  // the indices between which the value is or the exact index.
  //
  // index_low, index_high, are set to the indices if a value is between sample
  // points, otherwise if there is an exact match then index_mid is set.
  // 
  // Returns 0 on error, 1 if indices found, 2 if exact index is found.
  uint8_t find_indices(uint16_t ADC_reading, 
                      const Temp_ADC_t table[],
                      int8_t dir, 
                      uint16_t* index_low, 
                      uint16_t* index_high, 
                      uint16_t* index_mid, 
                      uint16_t table_size)
  {
      uint8_t found = 0;
      uint16_t mid, low, high;
      low = 0;
      high = table_size - 1;
  
      if((table != NULL) &amp;&amp; (table_size &gt; 0) &amp;&amp; (index_low != NULL) &amp;&amp;
         (index_mid != NULL) &amp;&amp; (index_high != NULL))
      {
          while(found == 0)
          {
              mid = (low + high) / 2;
  
              if(table[mid].ADC == ADC_reading)
              {   
                  // exact match                       
                  found = 2;            
              }
              else if(table[mid].ADC &lt; ADC_reading)
              {
                  if(table[mid + dir].ADC == ADC_reading)
                  {
                      // exact match          
                      found = 2;
                      mid = mid + dir;                             
                  }
                  else if(table[mid + dir].ADC &gt; ADC_reading)
                  {
                      // found the two indices
                      found = 1;
                      low = (dir == 1)? mid : (mid + dir);
                      high = (dir == 1)? (mid + dir) : mid;                            
                  }
                  else if(table[mid + dir].ADC &lt; ADC_reading)
                  {                     
                      low = (dir == 1)? (mid + dir) : low;
                      high = (dir == 1) ? high : (mid + dir);
                  }              
              }
              else if(table[mid].ADC &gt; ADC_reading)
              {
                  if(table[mid - dir].ADC == ADC_reading)
                  {
                      // exact match          
                      found = 2;
                      mid = mid - dir;                             
                  }
                  else if(table[mid - dir].ADC &lt; ADC_reading)
                  {
                      // found the two indices
                      found = 1;
                      low = (dir == 1)? (mid - dir) : mid;
                      high = (dir == 1)? mid : (mid - dir);                            
                  }
                  else if(table[mid - dir].ADC &gt; ADC_reading)
                  {
                      low = (dir == 1)? low : (mid - dir);
                      high = (dir == 1) ? (mid - dir) : high;
                  }
              } 
          }        
          *index_low = low;
          *index_high = high;
          *index_mid = mid;        
      }
  
      return found;  
  }
  
  // This function uses the lookup table provided as an input argument to find the
  // temperature for a ADC value using linear approximation. 
  // 
  // Temperature value is set using the temp pointer.  
  // 
  // Return 0 if an error occured, 1 if an approximate result is calculate, 2
  // if the sample value match is found.
  
  uint8_t lookup_temp(uint16_t ADC_reading, const Temp_ADC_t table[], 
                      uint16_t table_size ,int8_t* temp)
  {
      uint16_t mid, low, high;
      int8_t dir;
      uint8_t return_code = 1;
      float gradient, offset;
  
      low = 0;
      high = table_size - 1;
  
      if((table != NULL) &amp;&amp; (temp != NULL) &amp;&amp; (table_size &gt; 0))
      {
          // Check if ADC_reading is out of bound and find if values are
          // increasing or decreasing along the table.
          if(table[low].ADC &lt; table[high].ADC)
          {
              if(table[low].ADC &gt; ADC_reading)
              {
                  return_code = 0;                                    
              }
              else if(table[high].ADC &lt; ADC_reading)
              {
                  return_code = 0;
              }
              dir = 1;
          }    
          else
          {
              if(table[low].ADC &lt; ADC_reading)
              {
                  return_code = 0;                                    
              }
              else if(table[high].ADC &gt; ADC_reading)
              {
                  return_code = 0;
              }
              dir = -1; 
          }
      }
      else
      {
          return_code = 0;    
      } 
  
      // determine the temperature by interpolating
      if(return_code &gt; 0)
      {
          return_code = find_indices(ADC_reading, table, dir, &amp;low, &amp;high, &amp;mid, 
                                     table_size);
  
          if(return_code == 2)
          {
              *temp = table[mid].temp;
          }
          else if(return_code == 1)
          {
              gradient = ((float)(table[high].temp - table[low].temp)) / 
                         ((float)(table[high].ADC - table[low].ADC));
              offset = (float)table[low].temp - gradient * table[low].ADC;
              *temp = (int8_t)(gradient * ADC_reading + offset);
          }
      }  
  
      return return_code;   
  }
  
  
  
  int main(int argc, char *argv[])
  {
    int8_t temp = 0;
    uint8_t x = 0;  
    uint16_t u = 0;
    uint8_t return_code = 0; 
    uint8_t i;
  
    //Print Table
    printf("Lookup Table:\n");
    for(i = 0; i &lt; TEMP_ADC_TABLE_SIZE; i++)
    {
        printf("%d,%d\n", temp_ADC[i].temp, temp_ADC[i].ADC);                
    }
  
    // Test case 1
    printf("Test case 1: Find the temperature for ADC Reading of 317\n");
    printf("Temperature should be 95 Return Code should be 1\n");
    return_code = lookup_temp(317, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Temperature: %d C\n", temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 2  
    printf("Test case 2: Find the temperature for ADC Reading of 595 (sample value)\n");
    printf("Temperature should be -10, Return Code should be 2\n");
    return_code = lookup_temp(595, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Temperature: %d C\n", temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 3  
    printf("Test case 3: Find the temperature for ADC Reading of 900 (out of bound - lower)\n");
    printf("Return Code should be 0\n");
    return_code = lookup_temp(900, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 4 
    printf("Test case 4: Find the temperature for ADC Reading of 300 (out of bound - Upper)\n");
    printf("Return Code should be 0\n");
    return_code = lookup_temp(300, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 5
    printf("Test case 5: NULL pointer (Table pointer) handling\n");
    printf("Return Code should be 0\n");
    return_code = lookup_temp(595, NULL, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 6
    printf("Test case 6: NULL pointer (temperature result pointer) handling\n");
    printf("Return Code should be 0\n");
    return_code = lookup_temp(595, temp_ADC, TEMP_ADC_TABLE_SIZE, NULL);
    printf("Return code: %d\n", return_code);
  
    // Test case 7
    printf("Test case 7: Find the temperature for ADC Reading of 620\n");
    printf("Temperature should be -14 Return Code should be 1\n");
    return_code = lookup_temp(630, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Temperature: %d C\n", temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 8
    printf("Test case 8: Find the temperature for ADC Reading of 880 (First table element test)\n");
    printf("Temperature should be -40 Return Code should be 2\n");
    return_code = lookup_temp(880, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Temperature: %d C\n", temp);
    printf("Return code: %d\n\n", return_code);
  
    // Test case 9
    printf("Test case 9: Find the temperature for ADC Reading of 310 (Last table element test)\n");
    printf("Temperature should be 100 Return Code should be 2\n");
    return_code = lookup_temp(310, temp_ADC, TEMP_ADC_TABLE_SIZE, &amp;temp);
    printf("Temperature: %d C\n", temp);
    printf("Return code: %d\n\n", return_code);  
  
    printf("Press ENTER to continue...\n");  
    getchar();
    return 0;
  }
  </code></pre>