Arm Mbed OS support forum

Sprintf with "%03X" does not left pad with "0"

I’m porting code from an Arduino application. The following code produces the correct char array in Arduino:

char hexval[5];
int gatetime= 124;
sprintf(&hexval[0], “%03X”, gatetime);

This produces 07C which is what i need to communicate with the sensor

When I try this code in Mbed, I only get “7C”.

Why is that?

I assume you are using Mbed OS6. OS6 uses minimal-printf library which does not support padding. You can switch back to the standard library by overriding the parameter in mbed_app.json.

    "target_overrides": {
        "*": {
            "target.printf_lib": "std"
        }
    }

More info here:

Thanks Kentaro.
I changed mbed_app.json to

{
“requires”: [“bare-metal”],
“target_overrides”: {
“*”: {
“target.printf_lib”: “std”
}
}
}

Now I am getting a segmentation error:

Do you want to show us your code?

How can I figure out where my files are located? It’s not obvious from MBed Studio

Here are the essential files:

#include “WylerZerotronicSensor.h”

#include “WylerUtils.h”

#include “mbed.h”

#include

#include

#include

class WylerInterface

{

public:

enum WylerCommand

{

    WriteGateTime = 0,

    ReadSensorAngle = 1,

    ReadZeroOffset = 2,

    WriteZeroOffset = 3

};

enum ZeroOffsetByte

{

    ZeroOffsetByte0 = 0,

    ZeroOffsetByte1 = 1,

    ZeroOffsetByte2 = 2,

    ZeroOffsetByte3 = 3,

    Nothing = 4

};

enum NachrichtenTyp

{

    Sensornachricht = 17,

    BestaetigungSensornachricht = 18,

    Statusabfrage = 33,

    Statusmeldung = 34,

    AktivierungTransparenteTCPVerbindung = 49,

    BestaetigungTransparenteTCPVerbindung = 50

};

bool VERBOSE;

WylerZerotronicSensor *sensor;

WylerCommand cmd_w;

//WylerUtils *wu;

void init(bool v)

{

    this->VERBOSE = v;

}

/// <summary>

/// use reduced command set and send through SendCommand to

/// get the tildes and other trappings

/// </summary>

/// <param name="devAddr"></param>

/// <param name="cmd"></param>

/// <param name="zob"></param>

/// <param name="sNewZeroOffset"></param>

/// <returns></returns>

const char *GetWylerRS485CommandExt(int devAddr, WylerCommand cmd, ZeroOffsetByte zob, float sNewZeroOffsetOrGateTime = 1000)

{

    bool verbose = VERBOSE;

    const char *strCommand = "~~~~";

    if (!(this->sensor)) // equal NULL

        this->sensor = new WylerZerotronicSensor();

    sensor->SetDeviceAddress(devAddr);

    /* #region  WylerCommands */

    switch (cmd)

    {

    case WriteGateTime:

    {

        // set measure interval <WriteGateTime> to sensor

        // assume that rs 485/sensor address 1, address range is  0...255  each addr. is unique; addr 0 & 255 are for broadcast only

        // use levelmeter 2000 to set the rs 485/sensor address

        // gate time = 1000ms = 499 = 1F3 (hex);

        // time calculation:  ((time [ms] / 2)-1) = value (dec) -> convert to hex

        //  how to set command string together:

        //

        //  section:        explaination                                example string (part)

        //  -------         ------------                                ---------------------

        //  rs 485 addr:    set in sendCommand, when no sensor is passed over, "FF" is taken

        //  subaddr:        always 1 except ZeroMATIC 1=x, 2=y          :         "1"

        //  opcode:         writegate = opcode A(hex), see manual       :          "A"

        //  data:           format depends on command, check manual

        //  "A003A0" is fixed, following of 1F3 timevalue(3 nibbles)    :           "A003A01F3"

        //  Checksum:       set in sendCommand

        int gatetime = (int)(sNewZeroOffsetOrGateTime) / 2 - 1;

        formatPrint("GetWylerRS485Command:gatetime:", gatetime, verbose);

        //convert gatetime to hexadecimal string

        char res[5]; /* two bytes of hex = 4 characters, plus NULL terminator */

        if (gatetime <= 0xFFFF)

            sprintf(&res[0], "%03x", gatetime);

        formatPrint("GetWylerRS485Command:res:", res, verbose);

        charArrayUpper(res);

        char _tmpCommand[7] = "A003A0";

        strcat(_tmpCommand, res);

        strCommand = CreateSendCommandExt(this->sensor, _tmpCommand, 1);

        formatPrint("GetWylerRS485Command:strCommand:", strCommand, verbose);

        //free(_tmpCommand);

    }

    break;

    case ReadSensorAngle:

    {

        // how to set command string together:

        //

        //  rs 485 addr:    set in sendCommand

        //  subaddr:        always 1 except ZeroMATIC 1=x, 2=y          :         "1"

        //  opcode:         ReadAngle = opcode D(hex), see manual       :          "D"

        //  data:           format depends on command, check manual

        //                  "D00000000" is fixed                        :           "00000000"

        //  Checksum:       set in sendCommand

        const char tmpCommand_ReadSensorAngle[10] = "D00000000"; // command without checksum

        strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ReadSensorAngle, 0);

        formatPrint("GetWylerRS485Command:strCommand:", strCommand, verbose);

    }

    break;

    case ReadZeroOffset:

    {

        switch (zob)

        {

        case ZeroOffsetByte0:

        {

            const char tmpCommand_ZeroOffsetByte0[10] = "200000200"; // EEPROM addr 2 (hex) -> ReadEEProm EEPROM[2] = ZeroOffset.Byte0

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte0, 0);

        }

        break;

        case ZeroOffsetByte1:

        {

            const char tmpCommand_ZeroOffsetByte1[10] = "200000300"; // EEPROM addr 3 (hex) -> ReadEEProm EEPROM[3] = ZeroOffset.Byte1

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte1, 0);

        }

        break;

        case ZeroOffsetByte2:

        {

            const char tmpCommand_ZeroOffsetByte2[10] = "200000400"; // EEPROM addr 4 (hex) -> ReadEEProm EEPROM[4] = ZeroOffset.Byte2

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte2, 0);

        }

        break;

        case ZeroOffsetByte3:

        {

            const char tmpCommand_ZeroOffsetByte3[10] = "200000500"; // EEPROM addr 5 (hex) -> ReadEEProm EEPROM[5] = ZeroOffset.Byte3

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte3, 0);

        }

        break;

        case Nothing:

        {

            strCommand = "";

        }

        break;

        }

    }

    break;

    case WriteZeroOffset:

    {

        sensor->uZeroOffset.nF32 = sNewZeroOffsetOrGateTime;

        switch (zob)

        {

        case ZeroOffsetByte0:

        {

            char *strDataByte_ZeroOffsetByte0 = byte9ToChars(sensor->uZeroOffset.nU8_0); // convert sum to hex string ( format 2 letters)

            char tmpCommand_ZeroOffsetByte0[8];

            strcpy(tmpCommand_ZeroOffsetByte0, "C005002");

            strcat(tmpCommand_ZeroOffsetByte0, strDataByte_ZeroOffsetByte0);

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte0, 0);

            free(strDataByte_ZeroOffsetByte0);

        }

        break;

        case ZeroOffsetByte1:

        {

            char *strDataByte_ZeroOffsetByte1 = byte9ToChars(sensor->uZeroOffset.nU8_1); // convert sum to hex string ( format 2 letters)

            char tmpCommand_ZeroOffsetByte1[8];

            strcpy(tmpCommand_ZeroOffsetByte1, "C005003");

            strcat(tmpCommand_ZeroOffsetByte1, strDataByte_ZeroOffsetByte1);

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte1, 0);

            free(strDataByte_ZeroOffsetByte1);

        }

        break;

        case ZeroOffsetByte2:

        {

            char *strDataByte_ZeroOffsetByte2 = byte9ToChars(sensor->uZeroOffset.nU8_2); // convert sum to hex string ( format 2 letters)

            char tmpCommand_ZeroOffsetByte2[8];

            strcpy(tmpCommand_ZeroOffsetByte2, "C005004");

            strcat(tmpCommand_ZeroOffsetByte2, strDataByte_ZeroOffsetByte2);

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte2, 0);

            free(strDataByte_ZeroOffsetByte2);

        }

        break;

        case ZeroOffsetByte3:

        {

            char *strDataByte_ZeroOffsetByte3 = byte9ToChars(sensor->uZeroOffset.nU8_3); // convert sum to hex string ( format 2 letters)

            char tmpCommand_ZeroOffsetByte3[8];

            strcpy(tmpCommand_ZeroOffsetByte3, "C005005");

            strcat(tmpCommand_ZeroOffsetByte3, strDataByte_ZeroOffsetByte3);

            strCommand = CreateSendCommandExt(this->sensor, tmpCommand_ZeroOffsetByte3, 0);

            free(strDataByte_ZeroOffsetByte3);

        }

        break;

        case Nothing:

        {

            strCommand = "";

        }

        break;

        }

    }

    break;

    }

    /* #endregion */

    formatPrint("GetWylerRS485CommandExt:strCommand:", strCommand, VERBOSE);

    return strCommand;

}

////////////////////////////////////////////////////////////////////////////////

// string sendCommand(string _command)

//

// put together the complete command and send it to the serial IO

//

// param: command to send

// return: void

char *CreateSendCommandExt(WylerZerotronicSensor *sensor, const char *_command, bool verbose)

{

    formatPrint("CreateSendCommandExt:_command:", _command, verbose);

    char strCommandToSend[1024] = "";

    char hexbuffer[5];

    char sCommand[1024] = "";

    if (sensor != NULL) // NOT equal NULL //&sensor

    {

        strcat(sCommand, sensor->sDeviceAddressAsChararray); // sensor->sDeviceAddress);

        formatPrint("CreateSendCommandExt:sCommand[sensor->sDeviceAddressAsChar()]:", sCommand, verbose);

        strcat(sCommand, "1");

        formatPrint("CreateSendCommandExt:sCommand[1]:", sCommand, verbose);

        strcat(sCommand, _command);

        formatPrint("CreateSendCommandExt:sCommand[_command]:", sCommand, verbose);

    }

    else

    {

        strcat(sCommand, "00");

        strcat(sCommand, _command);

    }

    calcCommandChecksumExt(sCommand, hexbuffer, verbose);

    formatPrint("CreateSendCommandExt:hexbuffer:", hexbuffer, verbose);

    //char checkSumCmd[14] = "011AA003A01F3";

    char nibbles[9] = "~~~~~~~~";

    strcat(strCommandToSend, nibbles);

    formatPrint("CreateSendCommandExt:strCommandToSend[nibbles]:", strCommandToSend, verbose);

    strcat(strCommandToSend, sCommand);

    formatPrint("CreateSendCommandExt:strCommandToSend[sCommand]:", strCommandToSend, verbose);

    strcat(strCommandToSend, hexbuffer);

    strcat(strCommandToSend, "\r");

    formatPrint("CreateSendCommandExt:strCommandToSend:", strCommandToSend, verbose);

    char *dup = (char *)malloc(strlen(strCommandToSend) + 1);

    return dup ? strcpy(dup, strCommandToSend) : dup;

}

};

WlyerZerotronicSensor:

/*

  • WylerZerotronicSensor.h

  • Created on: Jun 6, 2020

  •  Author: p26953
    

*/

#ifndef WYLERZEROTRONICSENSOR_H_

#define WYLERZEROTRONICSENSOR_H_

#pragma once

#include “mbed.h”

//#include “main.h”

#include “WylerUtils.h”

#include

/////////

//NOT SUPPORTED YET

////////

//#include <Arduino.h>

// This union is used to convert 4 Bytes (UInt8) into a Single, a UInt32 or a UInt16.

struct WyBusUNION32

{

public:

//[FieldOffset(0)]

BYTE nU8_0;

//[FieldOffset(1)]

BYTE nU8_1;

//[FieldOffset(2)]

BYTE nU8_2;

//[FieldOffset(3)]

BYTE nU8_3;

//[FieldOffset(0)]

uint16_t nU16;

//[FieldOffset(0)]

uint32_t nU32;

//[FieldOffset(0)]

float nF32;

};

class WylerZerotronicSensor

{

public:

bool VERBOSE;

int nDeviceAddress = -1;

//String sDeviceAddressString;

char sDeviceAddressAsChararray[5];

WyBusUNION32 uZeroOffset;

int nSequenceNumber;

float fAngle;

union {

    int source;

    char tgt[sizeof(int)];

} converter;

void init(bool v)

{

    VERBOSE = v;

}

void SetDeviceAddress(int nDevAddress)

{

    //lets be sure our integer is in desired range

 int maxAdress = std::max(nDevAddress, 0);

    nDeviceAddress = std::min(maxAdress, 65535);

    //buffer big enough for 4 hex digits + terminating null

    //char hexbuffer[5];

    //sprintf(hexbuffer, "%02x", nDeviceAddress);

    //sDeviceAddressString = hexbuffer; //.ToString("X2");

    formatPrint("SetDeviceAddress:nDevAddress:", nDevAddress, VERBOSE);

    //formatPrint("SetDeviceAddress:hexbuffer:", hexbuffer, VERBOSE);

    //sDeviceAddressAsChararray[0] = '0';

    sprintf(sDeviceAddressAsChararray, "%02x", nDeviceAddress);

    charArrayUpper(sDeviceAddressAsChararray);

    formatPrint("SetDeviceAddress:sDeviceAddressAsChararray:", sDeviceAddressAsChararray, VERBOSE);

}

};

#endif /* WYLERZEROTRONICSENSOR1_H_ */

Sorry, I don’t know. I don’t use Studio… But what files are you looking for?

This code below works on my LPC1768 (OS 6.0.0).

int main() {
    char hexval[5];
    int gatetime= 124;
    sprintf(&hexval[0], "%03X", gatetime);
    printf("gatetime: %s \n", hexval);
}
// gatetime: 07C

Maybe there is something wrong (like buffer overflow) with your main.cpp.

Thanks, I will try it!

I found the project files. When I move the mouse over the tab of a file in MBed Studio, you can see where the project files are located.

Is this correct?

{
“requires”: [“bare-metal”],
“target_overrides”: {
“*”: {
“target.printf_lib”: “std”
}
}
}

Please use code blocks when you paste codes. You can open and close a code block by placing triple backticks.

```
// your code
```

Here is my mbed_app.json.

{
	"requires": ["bare-metal"],
	"target_overrides": {
	    "*": {
	        "target.printf_lib": "std"
	    }
	}
}

Thx, but I don’t have backticks on my (German) keyboard, only single quotation marks

Usually, the google is good friend.

But according to this it seems ALT+96 is universal, maybe.

BR, Jan

I managed to find the error by incrementally moving a return statement down in the method readVal.
When I now try to debug the program, I get the following error:

OSError: exception: access violation writing 0x0000000000000024

What could this be?