Using the new Arduino IDE for ESP8266 and found bugs, report them here

Moderator: igrr

User avatar
By martinayotte
#25108 I got the fix : I took odometer version of dtostrf() replacement and add a NULL character at the end of the string before the return.

This means the dtostrf() replacement is the following in cores/esp8266/core_esp8266_noniso.c :

Code: Select allchar * dtostrf(double number, signed char width, unsigned char prec, char *s) {

    if(isnan(number)) {
        strcpy(s, "nan");
        return s;
    }
    if(isinf(number)) {
        strcpy(s, "inf");
        return s;
    }

    if(number > 4294967040.0 || number < -4294967040.0) {
        strcpy(s, "ovf");
        return s;
    }
    char* out = s;
    // Handle negative numbers
    if(number < 0.0) {
        *out = '-';
        ++out;
        number = -number;
    }

    // Round correctly so that print(1.999, 2) prints as "2.00"
    // I optimized out most of the divisions
    double rounding = 2.0;
    for(uint8_t i = 0; i < prec; ++i)
        rounding *= 10.0;       
    rounding = 1.0 / rounding;   

    number += rounding;

    // Extract the integer part of the number and print it
    unsigned long int_part = (unsigned long) number;
    double remainder = number - (double) int_part;
    out += sprintf(out, "%d", int_part);

    // Print the decimal point, but only if there are digits beyond
    if(prec > 0) {
        *out = '.';
        ++out;
    }

    // Print the digits after the decimal point
    int8_t digit = 0;
    while(prec-- > 0) {
        remainder *= 10.0;
        digit = (int8_t)remainder;
        if (digit > 9) digit = 9; // insurance
        *out = (char)('0' | digit);
        ++out;
        remainder -= digit;
    }
   *out = 0;
    return s;
}
User avatar
By trackerj
#25200
martinayotte wrote:I got the fix : I took odometer version of dtostrf() replacement and add a NULL character at the end of the string before the return.

This means the dtostrf() replacement is the following in cores/esp8266/core_esp8266_noniso.c :

Code: Select allchar * dtostrf(double number, signed char width, unsigned char prec, char *s) {

    if(isnan(number)) {
        strcpy(s, "nan");
        return s;
    }
    if(isinf(number)) {
        strcpy(s, "inf");
        return s;
    }

    if(number > 4294967040.0 || number < -4294967040.0) {
        strcpy(s, "ovf");
        return s;
    }
    char* out = s;
    // Handle negative numbers
    if(number < 0.0) {
        *out = '-';
        ++out;
        number = -number;
    }

    // Round correctly so that print(1.999, 2) prints as "2.00"
    // I optimized out most of the divisions
    double rounding = 2.0;
    for(uint8_t i = 0; i < prec; ++i)
        rounding *= 10.0;       
    rounding = 1.0 / rounding;   

    number += rounding;

    // Extract the integer part of the number and print it
    unsigned long int_part = (unsigned long) number;
    double remainder = number - (double) int_part;
    out += sprintf(out, "%d", int_part);

    // Print the decimal point, but only if there are digits beyond
    if(prec > 0) {
        *out = '.';
        ++out;
    }

    // Print the digits after the decimal point
    int8_t digit = 0;
    while(prec-- > 0) {
        remainder *= 10.0;
        digit = (int8_t)remainder;
        if (digit > 9) digit = 9; // insurance
        *out = (char)('0' | digit);
        ++out;
        remainder -= digit;
    }
   *out = 0;
    return s;
}


Looks like properly terminating the string is doing properly the job. If anybody else want to test ... will be great to have more feedback about :)
User avatar
By martinayotte
#25412 I've got PM exchange with Odometer, and he gave me new contribution for better left padding, I've also changed tthe minus sign position (I've already commit, hoping that IGRR will bring that in the main branch soon)

Here is the new version :

Code: Select allchar * dtostrf(double number, signed char width, unsigned char prec, char *s) {
    bool negative = false;
   
    if (isnan(number)) {
        strcpy(s, "nan");
        return s;
    }
    if (isinf(number)) {
        strcpy(s, "inf");
        return s;
    }

    char* out = s;
   
    int fillme = width; // how many cells to fill for the integer part
    if (prec > 0) {
        fillme -= (prec+1);
    }
   
    // Handle negative numbers
    if (number < 0.0) {
        negative = true;
        fillme--;
        number = -number;
    }

    // Round correctly so that print(1.999, 2) prints as "2.00"
    // I optimized out most of the divisions
    double rounding = 2.0;
    for (uint8_t i = 0; i < prec; ++i)
        rounding *= 10.0;     
    rounding = 1.0 / rounding;

    number += rounding;
   
    // Figure out how big our number really is
    double tenpow = 1.0;
    int digitcount = 1;
    while (number >= 10.0 * tenpow) {
        tenpow *= 10.0;   
        digitcount++;
    }
   
    number /= tenpow;
    fillme -= digitcount;
   
    // Pad unused cells with spaces
    while (fillme-- > 0) {
        *out++ = ' ';
    }
   
    // Handle negative sign
    if (negative) *out++ = '-';
   
    // Print the digits, and if necessary, the decimal point
    digitcount += prec;
    int8_t digit = 0;
    while (digitcount-- > 0) {       
        digit = (int8_t)number;
        if (digit > 9) digit = 9; // insurance
        *out++ = (char)('0' | digit);
        if ((digitcount == prec) && (prec > 0)) {
            *out++ = '.';
        }   
        number -= digit;
        number *= 10.0;
    }

    // make sure the string is terminated
    *out = 0;
    return s;
}