Ejemplo n.º 1
0
// this gets called when you get an SLA+R
void onRequestService(void){
    static uint8_t response[EGG_BUS_MAX_RESPONSE_LENGTH] = { 0 };
    uint8_t response_length = 4; // unless it gets overridden 4 is the default
    uint8_t sensor_index = 0;
    uint8_t sensor_field_offset = 0;
    uint16_t address = egg_bus_get_read_address(); // get the address requested in the SLA+W
    uint16_t sensor_block_relative_address = address - ((uint16_t) EGG_BUS_SENSOR_BLOCK_BASE_ADDRESS);
    uint16_t possible_values[3] = {0,0,0};
    uint32_t possible_low_side_resistances[3] = {0,0,0};
    uint8_t best_value_index = 0;
    uint32_t responseValue = 0;
    uint32_t temp = 0;
    switch(address){
    case EGG_BUS_ADDRESS_SENSOR_COUNT:
        response[0] = EGG_BUS_NUM_HOSTED_SENSORS;
        response_length = 1;
        break;
    case EGG_BUS_ADDRESS_MODULE_ID:
        memcpy(response, macaddr, 6);
        response_length = 6;
        break;
    case EGG_BUS_FIRMWARE_VERSION:
        big_endian_copy_uint32_to_buffer(EGG_BUS_FIRMWARE_VERSION_NUMBER, response);
        break;
#ifdef INCLUDE_DEBUG_REGISTERS
    case EGG_BUS_DEBUG_NO2_HEATER_VOLTAGE_PLUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_voltage(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_HEATER_VOLTAGE_MINUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_feedback_voltage(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_HEATER_POWER_MW:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_mw(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_DIGIPOT_WIPER:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_wiper1(), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_VOLTAGE_PLUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_voltage(1), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_VOLTAGE_MINUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_feedback_voltage(1), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_POWER_MW:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_mw(1), response);
        break;
    case EGG_BUS_DEBUG_CO_DIGIPOT_WIPER:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_wiper0(), response);
        break;
    case EGG_BUS_DEBUG_DIGIPOT_STATUS:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_status(), response);
        blinkLEDs(1, POWER_LED);
        break;
#endif
    default:
        if(address >= EGG_BUS_SENSOR_BLOCK_BASE_ADDRESS){
            sensor_index = sensor_block_relative_address / ((uint16_t) EGG_BUS_SENSOR_BLOCK_SIZE);
            sensor_field_offset = sensor_block_relative_address % ((uint16_t) EGG_BUS_SENSOR_BLOCK_SIZE);
            switch(sensor_field_offset){
            case EGG_BUS_SENSOR_BLOCK_TYPE_OFFSET:
                egg_bus_get_sensor_type(sensor_index, (char *) response);
                response_length = 16;
                break;
            case EGG_BUS_SENSOR_BLOCK_UNITS_OFFSET:
                egg_bus_get_sensor_units(sensor_index, (char *) response);
                response_length = 16;
                break;
            case EGG_BUS_SENSOR_BLOCK_R0_OFFSET:
                big_endian_copy_uint32_to_buffer(egg_bus_get_r0_ohms(sensor_index), response);
                break;
            case EGG_BUS_SENSOR_BLOCK_TABLE_X_SCALER_OFFSET:
                memcpy(&responseValue, get_p_x_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_TABLE_Y_SCALER_OFFSET:
                memcpy(&responseValue, get_p_y_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT_SCALER_OFFSET:
                memcpy(&responseValue, get_p_independent_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT_OFFSET:
            case EGG_BUS_SENSOR_BLOCK_RAW_VALUE_OFFSET:
                possible_low_side_resistances[0] = get_r1(sensor_index) + get_r2(sensor_index) + get_r3(sensor_index);
                possible_low_side_resistances[1] = get_r1(sensor_index) + get_r2(sensor_index);
                possible_low_side_resistances[2] = get_r1(sensor_index);

                // R2 and R3 enabled
                SENSOR_R2_ENABLE(sensor_index);
                SENSOR_R3_ENABLE(sensor_index);
                _delay_ms(10);
                possible_values[0] = averageADC(sensor_index);

                // R3 disabled
                SENSOR_R3_DISABLE(sensor_index);
                _delay_ms(10);
                possible_values[1] = averageADC(sensor_index);

                // R2 and R3 disabled
                SENSOR_R2_DISABLE(sensor_index);
                _delay_ms(10);
                possible_values[2] = averageADC(sensor_index);

                // i'm going to abuse some variables to save space here
                temp  = ((1024L * get_sensor_vcc(sensor_index)) / ADC_VCC_TENTH_VOLTS) / 2L; //midrange_adc_value
                responseValue = temp > possible_values[0] ? temp - possible_values[0] : possible_values[0] - temp; // responseValue = abs(adc_midpoint - adc[0])
                if(min32(responseValue, temp > possible_values[1] ? temp - possible_values[1] : possible_values[1] - temp) == responseValue){
                    best_value_index =  0;
                }
                else{
                    best_value_index = 1;
                    responseValue = temp > possible_values[1] ? temp - possible_values[0] : possible_values[1] - temp; // responseValue = abs(adc_midpoint - adc[1])
                }

                // responseValue is the smaller difference to the midpoint between adc[0] and adc[1]
                if(min32(responseValue, temp > possible_values[2] ? temp - possible_values[2] : possible_values[2] - temp) != responseValue){
                    best_value_index = 2;
                }

                if(sensor_field_offset == EGG_BUS_SENSOR_BLOCK_RAW_VALUE_OFFSET){
                    response_length = 20;
                    //the following returns the best value and the associated low side resistance
                    big_endian_copy_uint32_to_buffer((uint32_t) possible_values[best_value_index], response);
                    big_endian_copy_uint32_to_buffer((uint32_t) possible_low_side_resistances[best_value_index], response + 4 );
                    big_endian_copy_uint32_to_buffer((uint32_t) get_sensor_vcc(sensor_index), response + 8 );
                    big_endian_copy_uint32_to_buffer((uint32_t) ADC_VCC_TENTH_VOLTS, response + 12 );
                    big_endian_copy_uint32_to_buffer((uint32_t) 1024, response + 16 );

                    //the following returns the three ADC values and the algorithmic selection of the best one's index
                    //responseValue = ((uint32_t)possible_values[0]) << 16;
                    //responseValue |= possible_values[1];
                    //big_endian_copy_uint32_to_buffer(responseValue, response);
                    //responseValue = ((uint32_t)possible_values[2]) << 16;
                    //responseValue |= best_value_index;
                    //big_endian_copy_uint32_to_buffer(responseValue, response + 4);

                }
//                else{ // if sensor_field_offset == EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT
//
//                    if(possible_values[best_value_index] == 0){ // open circuit condition
//                        responseValue = 0xffffffff;
//                    }
//                    else if(best_value_index == 0 && possible_values[best_value_index] < get_sensor_min_adc_high_r(sensor_index)){ // resistance too large
//                        responseValue = 0xfffffffe;
//                    }
//                    else{
//                        // calculate the resistance
//                        // (sensor_vcc - sensor_v) * R_low / sensor_v = R_sensor
//
//                        responseValue = ADC_VCC_TENTH_VOLTS * possible_values[best_value_index];
//                        responseValue /= 1024L;
//
//                        // now responseValue is the sensor voltage in tenths of a volt
//
//                        temp = responseValue; // save sensor voltage for later
//
//                        responseValue = get_sensor_vcc(sensor_index) - temp;
//
//                        // now responseValue is the parenthetical numerator term
//
//                        responseValue *= possible_low_side_resistances[best_value_index];
//
//                        // now responseValue is the actual numerator
//
//                        responseValue /= temp;
//
//                        // now responseValue is the measured resistance
//
//                        temp = responseValue;
//                        responseValue *= get_independent_scaler_inverse(sensor_index);
//                        responseValue /= egg_bus_get_r0_ohms(sensor_index);
//                    }
//
//                    big_endian_copy_uint32_to_buffer(responseValue, response);
//                }
                break;
            default: // assume its an access to the mapping table entries
                sensor_block_relative_address = (sensor_field_offset - EGG_BUS_SENSOR_BLOCK_COMPUTED_VALUE_MAPPING_TABLE_BASE_OFFSET);
                sensor_block_relative_address >>= 3; // divide by eight - now it is the mapping table index
                response_length = 2;

                *(response)   = getTableValue(sensor_index, sensor_block_relative_address, 0);
                *(response+1) = getTableValue(sensor_index, sensor_block_relative_address, 1);

                break;
            }
        }
        break;
    }
Ejemplo n.º 2
0
// this gets called when you get an SLA+R
void onRequestService(void){
    uint8_t response[EGG_BUS_MAX_RESPONSE_LENGTH] = { 0 };
    uint8_t response_length = 4; // unless it gets overridden 4 is the default
    uint8_t sensor_index = 0;
    uint8_t sensor_field_offset = 0;
    uint16_t address = egg_bus_get_read_address(); // get the address requested in the SLA+W
    uint16_t sensor_block_relative_address = address - ((uint16_t) EGG_BUS_SENSOR_BLOCK_BASE_ADDRESS);
    uint16_t possible_values[3] = {0,0,0};
    uint32_t possible_low_side_resistances[3] = {0,0,0};
    uint8_t best_value_index = 0;
    uint32_t responseValue = 0;
    uint32_t temp = 0;
    switch(address){
    case EGG_BUS_ADDRESS_SENSOR_COUNT:
        response[0] = EGG_BUS_NUM_HOSTED_SENSORS;
        response_length = 1;
        break;
    case EGG_BUS_ADDRESS_MODULE_ID:
        memcpy(response, macaddr, 6);
        response_length = 6;
        break;
    case EGG_BUS_FIRMWARE_VERSION:
        big_endian_copy_uint32_to_buffer(EGG_BUS_FIRMWARE_VERSION_NUMBER, response);
        break;
#ifdef INCLUDE_DEBUG_REGISTERS
    case EGG_BUS_DEBUG_NO2_HEATER_VOLTAGE_PLUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_voltage(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_HEATER_VOLTAGE_MINUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_feedback_voltage(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_HEATER_POWER_MW:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_mw(0), response);
        break;
    case EGG_BUS_DEBUG_NO2_DIGIPOT_WIPER:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_wiper1(), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_VOLTAGE_PLUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_voltage(1), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_VOLTAGE_MINUS:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_feedback_voltage(1), response);
        break;
    case EGG_BUS_DEBUG_CO_HEATER_POWER_MW:
        big_endian_copy_uint32_to_buffer(heater_control_get_heater_power_mw(1), response);
        break;
    case EGG_BUS_DEBUG_CO_DIGIPOT_WIPER:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_wiper0(), response);
        break;
    case EGG_BUS_DEBUG_DIGIPOT_STATUS:
        big_endian_copy_uint32_to_buffer((uint32_t) digipot_read_status(), response);
        blinkLEDs(1, POWER_LED);
        break;
#endif
    default:
        if(address >= EGG_BUS_SENSOR_BLOCK_BASE_ADDRESS){
            sensor_index = sensor_block_relative_address / ((uint16_t) EGG_BUS_SENSOR_BLOCK_SIZE);
            sensor_field_offset = sensor_block_relative_address % ((uint16_t) EGG_BUS_SENSOR_BLOCK_SIZE);
            switch(sensor_field_offset){
            case EGG_BUS_SENSOR_BLOCK_TYPE_OFFSET:
                egg_bus_get_sensor_type(sensor_index, (char *) response);
                response_length = 16;
                break;
            case EGG_BUS_SENSOR_BLOCK_UNITS_OFFSET:
                egg_bus_get_sensor_units(sensor_index, (char *) response);
                response_length = 16;
                break;
            case EGG_BUS_SENSOR_BLOCK_R0_OFFSET:
                big_endian_copy_uint32_to_buffer(egg_bus_get_r0_ohms(sensor_index), response);
                break;
            case EGG_BUS_SENSOR_BLOCK_TABLE_X_SCALER_OFFSET:
                memcpy(&responseValue, get_p_x_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_TABLE_Y_SCALER_OFFSET:
                memcpy(&responseValue, get_p_y_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT_SCALER_OFFSET:
                memcpy(&responseValue, get_p_independent_scaler(sensor_index), 4);
                big_endian_copy_uint32_to_buffer(responseValue, response);
                break;
            case EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT_OFFSET:
            case EGG_BUS_SENSOR_BLOCK_RAW_VALUE_OFFSET:
                possible_low_side_resistances[0] = get_r1(sensor_index) + get_r2(sensor_index) + get_r3(sensor_index);
                possible_low_side_resistances[1] = get_r1(sensor_index) + get_r2(sensor_index);
                possible_low_side_resistances[2] = get_r1(sensor_index);

                // R2 and R3 enabled
                SENSOR_R2_ENABLE(sensor_index);
                SENSOR_R3_ENABLE(sensor_index);
                _delay_ms(10);
                possible_values[0] = averageADC(sensor_index);

                // R3 disabled
                SENSOR_R3_DISABLE(sensor_index);
                _delay_ms(10);
                possible_values[1] = averageADC(sensor_index);

                // R2 and R3 disabled
                SENSOR_R2_DISABLE(sensor_index);
                _delay_ms(10);
                possible_values[2] = averageADC(sensor_index);

                // figure out the "best value index" ... here's how this algorithm works:
                // If the ADC reading when using the R1 + R2 + R3 chain is below THRESHOLD1 use that value
                // else if the ADC reading when using the R1 + R2 chain is below THRESHOLD2 use that value
                // else use the ADC reading using the R1 chain
                if(possible_values[0] < get_r1r2r3_threshold(sensor_index)){
                    best_value_index = 0;
                }
                else if(possible_values[1] < get_r1r2_threshold(sensor_index)){
                    best_value_index = 1;
                }
                else{
                    best_value_index = 2;
                }

                if(sensor_field_offset == EGG_BUS_SENSOR_BLOCK_RAW_VALUE_OFFSET){
                    response_length = 8;
                    big_endian_copy_uint32_to_buffer((uint32_t) possible_values[best_value_index], response);
                    big_endian_copy_uint32_to_buffer((uint32_t) possible_low_side_resistances[best_value_index], response + 4 );
                }
                else{ // if sensor_field_offset == EGG_BUS_SENSOR_BLOCK_MEASURED_INDEPENDENT
                      // in either case ... calculate the resistance
                    uint32_t a = ((uint32_t) possible_values[best_value_index]) *  ADC_VCC_TENTH_VOLTS; // ADC_VCC * ADC
                    uint32_t b = (1024L * ((uint32_t) get_sensor_vcc(sensor_index))); // 1024 * SENSOR_VCC
                    if(a > b){
                        responseValue = 0; // short circuit
                    }
                    else{
                        // what we are computing is
                        // R_SENSOR = R_LOW_SIDE * SENSOR_VCC * (1024 * SENSOR_VCC - ADC_VCC * ADC) / (ADC_VCC * SENSOR_VCC * ADC)
                        //          = R_LOW_SIDE * SENSOR_VCC * (b - a) / (ADC_VCC * SENSOR_VCC * ADC)
                        responseValue = b - a;

                        // before we multiply by a potentially large value lets find out if it's going to make us overflow and avert that if possible
                        if(possible_low_side_resistances[best_value_index] > (((uint32_t) 0xffffffff) / responseValue) ){
                            if(possible_values[best_value_index] != 0){
                                responseValue /= ((uint32_t) ADC_VCC_TENTH_VOLTS);                 // (b - a) / (ADC_VCC)
                                responseValue *= possible_low_side_resistances[best_value_index];  // R_LOW_SIDE * (b - a) / (ADC_VCC)
                                responseValue /= ((uint32_t) get_sensor_vcc(sensor_index) *
                                        ((uint32_t) possible_values[best_value_index]));           // R_LOW_SIDE * (b - a) / (ADC_VCC * ADC * SENSOR_VCC)
                                responseValue *= get_sensor_vcc(sensor_index);                     // R_LOW_SIDE * SENSOR_VCC * (b - a) / (ADC_VCC * ADC * SENSOR_VCC)
                            }
                            else{
                                responseValue = 0xffffffff; // infinity
                            }
                        }
                        else{
                            responseValue *= possible_low_side_resistances[best_value_index];        // R_LOW_SIDE * (b - a)
                            if(possible_values[best_value_index] != 0){
                                responseValue /= ((uint32_t) possible_values[best_value_index]) *
                                        ((uint32_t) ADC_VCC_TENTH_VOLTS *
                                        ((uint32_t) get_sensor_vcc(sensor_index)));                // R_LOW_SIDE * (b - a) / (ADC * ADC_VCC * SENSOR_VCC)
                                responseValue *= get_sensor_vcc(sensor_index);                     // R_LOW_SIDE * SENSOR_VCC * (b - a) / (ADC * ADC_VCC * SENSOR_VCC)
                            }
                            else{
                                responseValue = 0xffffffff; // infinity
                            }
                        }
                    }

                    // the independent variable in either case is R_Sensed / R0
                    //float_response = ((1.0 * responseValue) / egg_bus_get_r0_ohms(sensor_index));
                    temp = responseValue;
                    responseValue *= get_independent_scaler_inverse(sensor_index);
                    if(temp > responseValue){
                        // overflow the independent variable should be returned as big as possible
                        responseValue = 0xffffffff; // infinity
                    }
                    else{
                        responseValue /= egg_bus_get_r0_ohms(sensor_index);
                    }
                    big_endian_copy_uint32_to_buffer(responseValue, response);
                }

                break;
            default: // assume its an access to the mapping table entries
                sensor_block_relative_address = (sensor_field_offset - EGG_BUS_SENSOR_BLOCK_COMPUTED_VALUE_MAPPING_TABLE_BASE_OFFSET);
                sensor_block_relative_address >>= 3; // divide by eight - now it is the mapping table index
                response_length = 2;

                *(response)   = getTableValue(sensor_index, sensor_block_relative_address, 0);
                *(response+1) = getTableValue(sensor_index, sensor_block_relative_address, 1);

                break;
            }
        }
        break;
    }