vsprintf, vsnprintf

Peter
Posts: 10
Joined: Fri Jan 09, 2015 3:00 pm

vsprintf, vsnprintf

Postby Peter » Tue Jan 20, 2015 11:04 am

Hi,
I need the functions vsprintf or vsnprintf . In libmain.a are defined: ets_vsprintf, ets_vsnprintf. I tried to call with the standard signature:
int ets_vsprintf(char *str, const char *format, char * argptr);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, char * argptr);

I want use it in

Code: Select all

sint8 ICACHE_FLASH_ATTR  espconn_printf(serverConnData *conn, const char *format, ...) {
#define MaxBuff 256
   char buffer[MaxBuff]; uint16 len;
   len = ets_vsprintf(buffer, format, (char *) ((&format)+1));
//or
   len = ets_vsnprintf(buffer, MaxBuff, MaxBuff-1, format, (char *) ((&format)+1));

...
later: write to buffer and call espconn_sent after serverSentCb.

But both call crashed: Fatal exception (28) with reboot.

How can I use ets_vsprintf , ets_vsnprintf ?

Peter

jcmvbkbc
Posts: 13
Joined: Fri Oct 24, 2014 7:27 pm

Re: vsprintf, vsnprintf

Postby jcmvbkbc » Tue Jan 20, 2015 11:27 am

Peter wrote:Hi,
I need the functions vsprintf or vsnprintf . In libmain.a are defined: ets_vsprintf, ets_vsnprintf. I tried to call with the standard signature:
int ets_vsprintf(char *str, const char *format, char * argptr);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, char * argptr);

These signatures don't look standard. The 'v' letter means that the function expects va_list parameter, so they should look like
int ets_vsprintf(char *str, const char *format, va_list arg);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, va_list arg);

Peter wrote:I want use it in

Code: Select all

sint8 ICACHE_FLASH_ATTR  espconn_printf(serverConnData *conn, const char *format, ...) {
#define MaxBuff 256
   char buffer[MaxBuff]; uint16 len;
   len = ets_vsprintf(buffer, format, (char *) ((&format)+1));
//or
   len = ets_vsnprintf(buffer, MaxBuff, MaxBuff-1, format, (char *) ((&format)+1));

...
later: write to buffer and call espconn_sent after serverSentCb.

But both call crashed: Fatal exception (28) with reboot.

How can I use ets_vsprintf , ets_vsnprintf ?

Try

Code: Select all

sint8 ICACHE_FLASH_ATTR  espconn_printf(serverConnData *conn, const char *format, ...) {
#define MaxBuff 256
   char buffer[MaxBuff]; uint16 len;
   va_list al;
   va_start(al, format);
   len = ets_vsprintf(buffer, format, al);
   va_end(al);

Peter
Posts: 10
Joined: Fri Jan 09, 2015 3:00 pm

Re: vsprintf, vsnprintf

Postby Peter » Tue Jan 20, 2015 4:06 pm

yes, but there is no va_list defined. And in \VC\crt\src\vadefs.h I find
typedef char * va_list;
So I tried also not successful

Code: Select all

typedef char *  va_list;
int ets_vsprintf(char *str, const char *format, va_list argptr);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, va_list argptr);

How is the definition of ets_vsprintf and ets_vsnprintf ?

jcmvbkbc
Posts: 13
Joined: Fri Oct 24, 2014 7:27 pm

Re: vsprintf, vsnprintf

Postby jcmvbkbc » Tue Jan 20, 2015 7:53 pm

Peter wrote:yes, but there is no va_list defined. And in \VC\crt\src\vadefs.h I find
typedef char * va_list;

I'm not sure what VC you're referring to. This type is defined in headers that come with the compiler and it's very architecture-specific.
On xtensa calling va_start is absolutely necessary for the correctness of va_list operation. Use #include <stdarg.h> to get its definition.

Peter
Posts: 10
Joined: Fri Jan 09, 2015 3:00 pm

Re: vsprintf, vsnprintf

Postby Peter » Wed Jan 21, 2015 5:55 am

Thanks, it works now.
in espmissingincludes.h

Code: Select all

#include <stdarg.h>
int ets_vsprintf(char *str, const char *format, va_list argptr);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer,  const char *format, va_list argptr);

Code: Select all

//send formatted output through espbuffsent
sint8 ICACHE_FLASH_ATTR  espbuffsentprintf(serverConnData *conn, const char *format, ...) {
#define MaxBuff 1024
   char buffer[MaxBuff]; uint16 len;
   va_list al;
   va_start(al, format);
   len = ets_vsnprintf(buffer, MaxBuff-1, format, al);
   va_end(al);
   if (len >= 0)
      return espbuffsent(conn, buffer, len);
   else
      return len;
}


It is for buffered send, waiting on serverSentCb befor call next espconn_sent . The other code work fine:

Code: Select all

static char txbuffer[MAX_CONN][MAX_TXBUFFER];
serverConnData connData[MAX_CONN];

//send all data in conn->txbuffer
//returns result from espconn_sent if data in buffer or ESPCONN_OK (0)
//only internal used by espbuffsent, serverSentCb
static sint8  ICACHE_FLASH_ATTR sendtxbuffer(serverConnData *conn) {
   sint8 result = ESPCONN_OK;
   if (conn->txbufferlen != 0)   {
      conn->readytosend = false;
      result= espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen);
      conn->txbufferlen = 0;   
      if (result != ESPCONN_OK)
         os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn);
   }
   return result;
}


//send string through espbuffsent
sint8 ICACHE_FLASH_ATTR espbuffsentstring(serverConnData *conn, const char *data) {
   return espbuffsent(conn, data, strlen(data));
}

//use espbuffsent instead of espconn_sent
//It solve problem: the next espconn_sent must after espconn_sent_callback of the pre-packet.
//Add data to the send buffer and send if previous send was completed it call sendtxbuffer and  espconn_sent
//Returns ESPCONN_OK (0) for success, -128 if buffer is full or error from  espconn_sent
sint8 ICACHE_FLASH_ATTR espbuffsent(serverConnData *conn, const char *data, uint16 len) {
   if (conn->txbufferlen + len > MAX_TXBUFFER) {
      os_printf("espbuffsent: txbuffer full on conn %p\n", conn);
      return -128;
   }
   os_memcpy(conn->txbuffer + conn->txbufferlen, data, len);
   conn->txbufferlen += len;
   if (conn->readytosend)
      return sendtxbuffer(conn);
   return ESPCONN_OK;
}
//callback after the data are sent
static void ICACHE_FLASH_ATTR serverSentCb(void *arg) {
   serverConnData *conn = serverFindConnData(arg);
   //os_printf("Sent callback on conn %p\n", conn);
   if (conn==NULL) return;
   conn->readytosend = true;
   sendtxbuffer(conn); // send possible new data in txbuffer
}

void ICACHE_FLASH_ATTR serverInit(int port) {
   int i;
   for (i = 0; i < MAX_CONN; i++) {
      connData[i].conn = NULL;
      connData[i].txbuffer = txbuffer[i];
      connData[i].txbufferlen = 0;
      connData[i].readytosend = true;
   }
   serverConn.type=ESPCONN_TCP;
   serverConn.state=ESPCONN_NONE;
   serverTcp.local_port=port;
   serverConn.proto.tcp=&serverTcp;

   espconn_regist_connectcb(&serverConn, serverConnectCb);
   espconn_accept(&serverConn);
   espconn_regist_time(&serverConn, SERVER_TIMEOUT, 0);
}



with
#define MAX_TXBUFFER 1024
struct serverConnData {
        struct espconn *conn;
      char *txbuffer; //the buffer for the data to send
      uint16  txbufferlen; //the length  of data in txbuffer
       bool readytosend; //true, if txbuffer can send by espconn_sent
};




Peter
Posts: 10
Joined: Fri Jan 09, 2015 3:00 pm

Re: vsprintf, vsnprintf

Postby Peter » Wed Jan 21, 2015 6:29 am

and a version to write direct in the transmit buffer

Code: Select all

//send formatted output to send buffer
sint8 ICACHE_FLASH_ATTR  espbuffsentprintf(serverConnData *conn, const char *format, ...) {
   uint16 len;
   va_list al;
   va_start(al, format);
   len = ets_vsnprintf(conn->txbuffer + conn->txbufferlen, MAX_TXBUFFER - conn->txbufferlen - 1, format, al);
   va_end(al);
   if (len <0)  {
      os_printf("espbuffsentprintf: txbuffer full on conn %p\n", conn);
      return len;
   }
   conn->txbufferlen += len;
   if (conn->readytosend)
      return sendtxbuffer(conn);
   return ESPCONN_OK;
}

smbgaiden
Posts: 5
Joined: Wed Oct 18, 2017 8:09 am

Re: vsprintf, vsnprintf

Postby smbgaiden » Wed Oct 18, 2017 8:23 am

Does anyone have advice on how to replicate this functionality?

I have nonOS SDK 2.1 with the xtensa includes from https://github.com/esp8266/esp8266-wiki ... nclude.tgz and using the crosstool-NG from jcmvbkbc. None of these produces a stdarg.h file to define va_list, va_start, va_arg, or va_end. Searching for espmissingincludes.h and downloading it I am able to find signatures for the ets_vsprintf function, but it includes stdarg.h also and lacks the file.

I don't have \VC\crt\src\vadefs.h as Peter does, but it seems that's likely no the right one to include.

Usually I can overcome the ambiguities on va_list in a similar manner to Peter by indexing to the correct stack location. Reading the Xtensa doc I see they do either stack based call0 or they do windowed registers. That's an area I don't know how to overcome to realise va_list and va_start.

Any pointers to replicate Peter's success are appreciated.

jcmvbkbc
Posts: 13
Joined: Fri Oct 24, 2014 7:27 pm

Re: vsprintf, vsnprintf

Postby jcmvbkbc » Wed Oct 18, 2017 2:01 pm

smbgaiden wrote:I have nonOS SDK 2.1 with the xtensa includes from https://github.com/esp8266/esp8266-wiki ... nclude.tgz and using the crosstool-NG

You should be able to find stdarg.h in the crosstool-NG build directory: xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.5/include/stdarg.h

smbgaiden
Posts: 5
Joined: Wed Oct 18, 2017 8:09 am

Re: vsprintf, vsnprintf

Postby smbgaiden » Thu Oct 19, 2017 1:37 am

Thank you, to update the thread this stdarg.h did solve my problem.

Who is online

Users browsing this forum: Google [Bot] and 7 guests