3

I am writing a code for modbus protocol, that runs on a MSP430 controller. The response buffer(global) is an array of 8bit data, through which the response to the processed request is to be sent on serial UART. Now, my problem is that the response generated is having a combination of different data types. i.e uint8, uint32, float. How to send this data by using the global response buffer?

For float, i have tried using memcpy and this seems to be working fine. Is there any better and efficient way? Cuz the frame size is large (say 20-30 bytes). Here is a demo of what i've tried to do

int main() 
{ unsigned char buff[8]; //Global buffer 

float temp[2]; //temp buffer to store response values 

temp[0] = 0x00ef2212; 

memcpy(buff, temp, 8); 

printf("buff[0]= %u \n buff[1]= %u\n buff[2] = %u\n buff[3]= %u\n", buff[0],buff[1],buff
[2],buff[3]); 

return 0; 
} 
OnkarK
  • 127
  • 2
  • 9

3 Answers3

1

With casting and assignment. E.g.

uint8 *globalbuf;
uint32 myval;
*(uint32*)globalbuf = myval;

copies myval into the first 4 bytes of globalbuf.

Beware of alignment issues: it may be illegal or expensive on your platform to assign or read values to/from addresses that aren't whole multiples of that type size. For example address 0,4,8 etc. are OK places to put a uint32.

This assumes your globalbuf starts on a nice round address..

blueshift
  • 6,742
  • 2
  • 39
  • 63
  • memcpy for most use cases is efficient enough. i would gather the entire response and then do a single memcpy .using typecasting *(*globalbuf) = val would be as efficient/expensive as memcpy and as mentioned by blueshift you could run into alignment issues. – keety Mar 22 '12 at 05:52
  • On the MSP430 a uint32, like a uint16, must start on an even byte boundary - 16 bit processor manipulates the uint32 in two 16 bit chunks. You can force the destination pointed by globalbuf to be on a uint16 boundary by defining a union of uint8 and uint16 arrays. The linker will place this data structure at a valid uint16 location. – uɐɪ Mar 23 '12 at 08:22
1

a simple implementation would be to create a response structure and memcpy the response structure to the buffer

struct response {
   uint8 bytedata;
   uint32 intdata;
   float  floatdata;
};
memcpy((void *)uartbuffer,(void *)&response,sizeof(response));

Note: since it looks like your working on a protocol the endianess may be already specified and you may need to pack items according to the particular endian type and simple memcpy would not work and you may need to pack the datatypes.

keety
  • 17,231
  • 4
  • 51
  • 56
  • The problem with this solution is that response may not be a combination of one u8, one u32 and one float. Cos this is the data part of the response frame(PDU), so, of variable length. It can be like say twenty u8's, one u32 and 2 floats. – OnkarK Mar 22 '12 at 06:06
  • @OnkarK how do you determine if the response frame represents 4 u8's or just 1 float ? – keety Mar 22 '12 at 06:20
  • I need to create a response frame for the request i have got. Say for a read request, i am going to send the data frm reqd addresses in my response to that request. – OnkarK Mar 22 '12 at 06:58
  • The structure above has a problem when representing the data packet that is transmitted across the MODBUS data link. There is at least one byte that is not used or defined between bytedata and intdata. When the data block is read out as a byte array, or received from the remote device again as a byte array, this empty byte will break the protocol. – uɐɪ Mar 23 '12 at 08:26
0

How about considering using a union to represent a same range of memory into different data types?

typedef union {
    unsigned char buff[8];
    float temp[2];
} un;

un global_buffer;
// give global_buffer.buff some data.
un local_buffer;

local_buffer = global_buffer; 
// handle local_buffer.temp
Wayne
  • 641
  • 6
  • 11
  • This isn't possible because the global buffer is already there and is being used by other modbus variants to send their responses. As i specified earlier, global buffer is an array of max 253 no's of one byte data. I can use such a union for creating a local buffer; but then still the problem of mapping it to a u8 array persists. I have no privilege to change the structure of the global response buffer cuz Modicon has it to make modbus communicate with a series of 1 byte data only! – OnkarK Mar 22 '12 at 07:48
  • you can define your own union or struct type and then overlay it on top of the buffer by having a pointer to your type and giving it the address of the global byte array. – uɐɪ Mar 23 '12 at 08:28
  • @Ian "overlay it on top of the buffer" dint understand this. Can u elaborate a li'l bit? – OnkarK Mar 23 '12 at 11:22