How to detect out of space error when mapping shared memory - mmap

The code is as follows:
fd = shm_open("Name", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
return -1;
}
rv = ftruncate(fd, 10 * 1024 * 1024);
if (rv != 0) {
return -1;
}
addr = mmap(NULL, 10 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
return -1;
}
/* Access the shared memory here and the program crashes */
Note that the size of /dev/shm is 30MB, and it's full before running the program. Instead of crashing, I would like to catch the out of space error and fail gracefully. However, mmap() doesn't return an error in this case. Is there a way for me to detect the out of space error?

Related

How to interact with the Linux PCA953X.c driver? How does one utilize this driver?

I have a PCA9535 GPIO Expander board connected through I²C to my Raspberry Pi. I am able to set the GPIO expander output pins (to high) using the i2cset command:
sudo i2cset 1 0x20 0x02 0xFF // 0x20 (gpio expander), and register 0x02
I came across a kernel driver for the PCA953X and loaded the kernel module gpio-pca953x.ko + modified the /boot/config.txt to include the dts overlay for the expander. When I run i2detect -y 1 (for i2c-1 bus), I can see "UU" at the 0x20 slave address, which corroborates that the driver is managing it.
If I wanted to do something comparable to what I did with the i2cset command programmatically, what API / interface should I use such that I make use of the PCA953X driver that's installed? As you can see from the code below, nothing there suggests that I would be utilizing PCA953X:
int file;
int adapter_nr = 1;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
file = open(filename, O_RDWR);
if (file < 0) {
exit(1);
}
// Writes 0xFF to register 0x02
uint8_t cmd[2] = {0x02, 0XFF};
struct i2c_msg msg = {
.addr = 0x20,
.flags = 0,
.len = sizeof(cmd)/sizeof(uint8_t),
.buf = cmd
};
struct i2c_rdwr_ioctl_data tx = {
.msgs = &msg,
.nmsgs = 1
};
ioctl(file, I2C_RDWR, &tx);
Is there a programming route that involves utilizing the PCA953X driver? What does having that module actually do?
Thanks to #TomV for pointing it out in the comments. The PCA953X driver provides a new character device in the form of "gpiochipN". In my case, it was gpiochip2. I had not noticed this extra gpiochip in /dev as I was not looking for it. Because this is a character device, I was able to use ioctl to interact with the lines:
int fd, ret;
fd = open("/dev/gpiochip2", O_RDONLY);
if (fd < 0) {
printf("Unable to open: %s", strerror(errno));
return;
}
struct gpiohandle_request req;
req.lineoffsets[0] = 0;
req.lineoffsets[1] = 1;
req.lineoffsets[2] = 2;
req.lineoffsets[3] = 3;
req.lineoffsets[4] = 4;
req.lineoffsets[5] = 5;
req.lineoffsets[6] = 6;
req.lineoffsets[7] = 7;
req.lines = 8;
req.flags = GPIOHANDLE_REQUEST_OUTPUT;
ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if (-1 == ret) {
printf("Failed to get line handle:%s\n", strerror(ret));
close(fd);
return;
}
// Sets all 8 lines to high (equivalent to setting register 0x3 to 0b11111111 or 0xFF)
struct gpiohandle_data data;
data.values[0] = 1;
data.values[1] = 1;
data.values[2] = 1;
data.values[3] = 1;
data.values[4] = 1;
data.values[5] = 1;
data.values[6] = 1;
data.values[7] = 1;
ret = ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
if (-1 == ret) {
printf("Failed to set line value\n");
}
else {
close(req.fd);
}
close(fd);
The above code interacts with the gpiochip2 character device, which is made possible by having the PCA953X installed. Without it, I would have to read and write to the registers through the i2c bus as was posted in my original question.

Problem writing FDC1004 registers with ESP32 in freeRTOS

I'm trying to read some capative sensors using FDC1004 connected to a ESP32 in freeRTOS. i'm having problems writing FDC1004 registers of 16bits. I programmed a test code reading the ID and writing the configuration registers. The read task is well, i can read correctly the ID of the FDC1004(0x1004), but when i tried to write the register i only read correctly the 8 LSBs. Here is my i2c functions:
esp_err_t I2C_write(i2c_port_t i2c_num, uint8_t slave_address, uint8_t data_address, uint8_t *data_wr ,size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_address << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data_address, ACK_CHECK_EN);
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
//i2c_master_write(cmd, data_addres, 1, ACK_CHECK_EN);
//i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
//i2c_master_write_byte(cmd, data_wr + size - 1, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000/portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
esp_err_t I2C_read(i2c_port_t i2c_num, uint8_t slave_address, uint8_t *data_addres, uint8_t *data_rd , size_t size){
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_address << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write(cmd, data_addres, size, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_address << 1) | READ_BIT, ACK_CHECK_EN);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
void FDC1004_writeReg(i2c_port_t i2c_num, uint8_t reg_address, uint16_t data){
uint8_t tx_buff[2];
tx_buff[0] = data >> 8;
tx_buff[1] = data & 0x00FF;
ESP_ERROR_CHECK(I2C_write( i2c_num, FDC_ADDR, reg_address, tx_buff, 2));
vTaskDelay(20 / portTICK_PERIOD_MS);
}
uint16_t FDC01004_readReg(i2c_port_t i2c_num, uint8_t reg_address){
uint8_t read_buff[2];
uint16_t data;
ESP_ERROR_CHECK(I2C_read( i2c_num, FDC_ADDR, &reg_address, read_buff, 2));
data = ((uint16_t)(read_buff[0] << 8) | read_buff[1]);
return data;
}
The results when i tried to write 0x10C0, 0x30C0, 0x50C0, 0x70C0 in the registers 0x08, 0x09, 0x0A and 0x0B respectively, are: 0xFFC0, 0xFFC0, 0xFFC0 and 0xFFC0, respectively.
I hope you can help me.
Regards
Finally, after some test with the code i change the read function as follow:
esp_err_t I2C_read(i2c_port_t i2c_num, uint8_t slave_address, uint8_t data_addres, uint8_t *data_rd , size_t size){
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_address << 1) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, data_addres, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_address << 1) | READ_BIT, ACK_CHECK_EN);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
The wrong thing in the read function was that it make a write of the reg address a size times, and only once was needed. This way works for me.

read bmp from sd card faster

i am working on Cy8CKIT -050 cypress kit, flash chip W25Q128FV ,SD card, and TFT display https://www.buydisplay.com/default/lcd-5-ssd1963-tft-module-touch-screen-display-800x480-mcu-arduino
i have interfaced display, flash chip using SPIFFS and sd card using FATFS with Cy8CKIT - 050
but the speed of BMP image loading from the sd card is very slow, right now size of image is 150*90 and its taking 635ms
how can i improve this?
also i want write BMP image from the sd card to Flash chip and load image from flash chip to display, how can i do that
i am attaching code for reference
`void DrawImage(UG_S16 x1, UG_S16 y1, UG_S16 x2, UG_S16 y2, const TCHAR* namefile)
{
FATFS fatFs;
FIL fileO;
uint16_t buffimg,buffimg1;
uint16_t buffer[1];
UINT br,br1;
FRESULT pt;
char read[50];
uint32_t bmpWidth = 0;
uint32_t bmpHeight = 0;
uint16_t bmpImageoffset;
uint16_t rowSize;
uint8_t rdBuf[60];
uint8_t header_buff[60];
uint16_t position = 0;
uint8_t numberOfPixels = 0;
uint32_t commpression = 0;
uint32_t imageSize = 0;
unsigned int byte_read;
uint16_t bmpSig;
uint8_t row_buff[rowSize]; // only read 1 row at a time
uint8_t cc,R,G,B;
uint16_t pixel;
uint16_t color;
uint32 i,j, count=0;
uint8_t pColorData[DISPLAY_WIDTH*3];
uint8_t pColorData_flash[DISPLAY_WIDTH*3];
uint8_t pColorData_flash1[DISPLAY_WIDTH*3];
uint32_t pos;
int row =0 ;
if((x1 < 0) ||(x1 >= DISPLAY_WIDTH) || (y1 < 0) || (y1 >= DISPLAY_HEIGHT)) return;
if((x2 < 0) ||(x2 >= DISPLAY_WIDTH) || (y2 < 0) || (y2 >= DISPLAY_HEIGHT)) return;
/* Mount drive */
pt = f_mount(&fatFs, "", 1);
if(pt != FR_OK) return;
/* open file */
pt = f_open(&fileO, namefile, FA_READ);
if(pt != FR_OK) return;
/* read bmp header */
pt = f_read(&fileO, header_buff, sizeof header_buff, &byte_read);
if(pt != FR_OK){
return;
}
//my_spiffs_mount();
//spiffs_file fd = SPIFFS_open(&fs, "bmpFile", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
//if (SPIFFS_write(&fs, fd,header_buff, sizeof(header_buff)) < 0) sprintf(bufferOut,"wr errno %i\n", SPIFFS_errno(&fs));
//SPIFFS_close(&fs, fd);
//UG_PutString(1,200,bufferOut);
//fd = SPIFFS_open(&fs, "bmpFile", SPIFFS_RDWR, 0);
//if (SPIFFS_read(&fs, fd, rdBuf, sizeof(rdBuf)) < 0) sprintf(bufferOut,"rd errno %i\n", SPIFFS_errno(&fs));
//SPIFFS_close(&fs, fd);
//UG_PutString(1,220,bufferOut);
bmpSig = (header_buff[1] << 8) | header_buff [0];
sprintf(bufferOut,"Signature:\t0x%X\n", bmpSig);
UG_PutString(1,160,bufferOut);
if(bmpSig != 0x4D42){
UG_PutString(1,180,"not a bmp");
return; // not a bmp
}
bmpImageoffset = header_buff [7] * 256 + header_buff [6];
bmpHeight = (header_buff [25] << 24) | (header_buff [24] << 16) | (header_buff [23] << 8) | header_buff [22];
bmpWidth = (header_buff [21] << 24) | (header_buff [20] << 16) | (header_buff [19] << 8) | header_buff [18];
position = header_buff [10]; // starting point in file
numberOfPixels = header_buff [29] * 256 + header_buff [28];
commpression = (header_buff [30] << 24) | (header_buff [31] << 16) | (header_buff [32] << 8) | header_buff [33];
imageSize = (header_buff [37] << 24) | (header_buff [36] << 16) | (header_buff [35] << 8) | header_buff [34];
rowSize = ((numberOfPixels * bmpWidth + 31) /32 ) * 4;
sprintf(read ,"Offset:\t%d\n", bmpImageoffset);
UG_PutString(1,1,read);
sprintf(read ,"Height:\t%u\n", bmpHeight);
UG_PutString(1,20,read);
sprintf(read ,"Width:\t\t%u\n", bmpWidth);
UG_PutString(1,40,read);
sprintf(read ,"Row Size:\t%d\n", rowSize);
UG_PutString(1,60,read);
sprintf(read ,"Start Index:\t%d\n", position);
UG_PutString(1,80,read);
sprintf(read ,"# of Pixels:\t%d\n", numberOfPixels);
UG_PutString(1,100,read);
sprintf(read ,"Compression:\t%u\n", commpression);
UG_PutString(1,120,read);
sprintf(read ,"Image Size:\t%u\n", imageSize);
UG_PutString(1,140,read);
Display_WindowSet(x1, x2, y1, y2);
/* Write to LCD-GRAM */
Display_WriteCommand(0x2c);
/* get current millisecond count */
unsigned long nCurrentMillis = nmillis;
for(i=0;i<bmpHeight; i++)
{
for(j=0; j<rowSize; j++)
{
count++;
LED3_Write(1);
f_read(&fileO,pColorData+j,1,&byte_read);
//fd = SPIFFS_open(&fs, "bmpFile", SPIFFS_RDWR , 0);
//if (SPIFFS_write(&fs, fd,pColorData+j, 1) < 0) sprintf(bufferOut,"wr errno %i\n", SPIFFS_errno(&fs));
//SPIFFS_close(&fs, fd);
//fd = SPIFFS_open(&fs, "bmpFile", SPIFFS_RDWR, 0);
//if (SPIFFS_read(&fs, fd, pColorData_flash+j, 1) < 0) sprintf(bufferOut,"rd errno %i\n", SPIFFS_errno(&fs));
//SPIFFS_close(&fs, fd);
//sprintf(bufferOut," row %lu",j);
//UG_PutString(1,360,bufferOut);
//CyDelay(1);
LED3_Write(0);
}
for(j=0;j<bmpWidth;j++)
{
//fd = SPIFFS_open(&fs, "bmpFile", SPIFFS_RDWR, 0);
//if (SPIFFS_read(&fs, fd, pColorData_flash,rowSize) < 0) sprintf(bufferOut,"rd errno %i\n", SPIFFS_errno(&fs));
//SPIFFS_close(&fs, fd);
uint32_t k = j*3;
R = pColorData[k+2];
G = pColorData[k+1];
B = pColorData[k];
color = color565(R,G,B);
Display_WriteData (color);
//sprintf(bufferOut," width %lu",j);
//UG_PutString(1,380,bufferOut);
}
//sprintf(bufferOut," height %lu",i);
//UG_PutString(1,400,bufferOut);
}
unsigned long nTime = nmillis-nCurrentMillis;
sprintf(bufferOut,"time taken for load : %lu ms",nTime);
UG_PutString(1,320,bufferOut);
sprintf(bufferOut,"%lu",count);
UG_PutString(1,340,bufferOut);
f_close(&fileO);
}
`

Select() System call hangs (does not pick up signal handler when disconnecting network cable)

I have the following problem that can't get my head around.
I have the following method (used in an embedded platform) that uses select():
int wait_fd_readable(int fd, long msec)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(fd, &rset);
struct timeval tv = { msec / 1000, (msec % 1000) * 1000 };
struct timeval *timeout = msec < 0 ? 0 : &tv;
return select(fd + 1, &rset, 0, 0, timeout);
}
It works very well in general, except when I disconnect the network cable where select seems to hang and never return -1 as expected.
Does anyone have any tip on why might that be?
Your problem seems to be in struct timeval *timeout = msec < 0 ? 0 : &tv; line:
If msec is negative, timeout is set to NULL, and your select call will wait infinitly.
From man select:
If timeout is NULL (no timeout), select() can block indefinitely.
Try to replace with:
int wait_fd_readable(int fd, long msec)
{
fd_set rset;
FD_ZERO(&rset);
FD_SET(fd, &rset);
if (msec < 0) {msec = 0;}
struct timeval tv = { msec / 1000, (msec % 1000) * 1000 };
return select(fd + 1, &rset, 0, 0, &tv);
}

Creating a packet as a string and then extracted its fields in C

I need to implement my own packets to send over UDP. I decided that I would do this by sending a char buffer which has the sequence number, checksum, size, and the data of the packet which is bytes from a file. The string i'm sending separates each field by a semicolon. Then, when I receive the string (which is my packet) I want to extract each felid, use them accordingly (the sequence number, size, and checksum) and write the bytes to a file. So far I have wrote a method to create 100 packets, and I'm trying to extract and write the bytes to a file (I'm not doing it in the receiver yet, first I'm testing the parsing in the sender). For some reason, the bytes written to my file are incorrect and I'm getting "JPEG DATATSTREAM CONTAINS NO IMAGE" error when I try to open it.
struct packetNode{
char packet[1052]; // this is the entire packet data including the header
struct packetNode *next;
};
This is how I'm creating my packets:
//populate initial window of size 100
for(i = 0; i < 100; i++){
memset(&data[0], 0, sizeof(data));
struct packetNode *p; // create packet node
p = (struct packetNode *)malloc(sizeof(struct packetNode));
bytes = fread(data, 1, sizeof(data), fp); // read 1024 bytes from file into data buffer
int b = fwrite(data, 1, bytes, fpNew);
printf("read: %d\n", bytes);
memset(&p->packet[0], 0, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
//calculate checksum
int check = checksum8(p->packet, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, check, numPackets, data); //put checksum in packet
s++; //incremenet sequence number
if(i == 0){
head = p;
tail = p;
tail->next = NULL;
}
else{
tail->next = p;
tail = p;
tail->next = NULL;
}
}
fclose(fp);
and this is where I parse and write the bytes to a file:
void test(){
FILE *fpNew = fopen("test.jpg", "w");
struct packetNode *ptr = head;
char *tokens;
int s, c, size;
int i = 0;
char data[1024];
while(ptr != NULL){
memset(&data[0], 0, sizeof(data));
tokens = strtok(ptr->packet,";");
s = atoi(tokens);
tokens = strtok(NULL, ";");
c = atoi(tokens);
tokens = strtok(NULL, ";");
size = atoi(tokens);
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
printf("sequence: %d, checksum: %d, size: %d\n", s,c,size);
int b = fwrite(data, 1, sizeof(data), fpNew);
ptr = ptr->next;
i++;
}
fclose(fpNew);
}
Since there is transfer of binary data, a JPEG stream, this data cannot be treated as a string. It's better to go all binary. For instance, instead of
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
you would do
sprintf(p->packet, "%d;%d;%d;", s, 0, numPackets);
memcpy(&p->packet[strlen(p->packet)], data, bytes);
but this leads to parsing problems: we would need to change this:
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
to something like this:
tokens += 1 + ( size < 10 ? 1 : size < 100 ? 2 : size < 1000 ? 3 : size < 10000 ? 4 : 5 );
memcpy(data, tokens, sizeof(data));
#Binary Protocol
It's easier to use a binary packet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma push(pack,1)
typedef struct Packet {
int seq, maxseq, size;
unsigned short cksum;
unsigned char payload[];
} Packet;
#pragma pop(pack)
typedef struct PacketNode{
struct PacketNode * next;
Packet packet;
} PacketNode;
PacketNode * allocPacketNode(int maxPayloadSize) {
void * ptr = malloc(sizeof(PacketNode) + maxPayloadSize); // FIXME: error checking
memset(ptr, 0, sizeof(PacketNode) + maxPayloadSize); // mallocz wouldn't cooperate
return (PacketNode*) ptr;
}
PacketNode * prepare(FILE * fp, int fsize, int chunksize)
{
PacketNode * head = allocPacketNode(chunksize);
PacketNode * pn = head;
int rd, seq = 0;
int maxseq = fsize / chunksize + ( fsize % chunksize ? 1 : 0 );
while ( ( rd = fread(pn->packet.payload, 1, chunksize, fp ) ) > 0 )
{
printf("read %d bytes\n", rd);
pn->packet.seq = seq++;
pn->packet.maxseq = maxseq;
pn->packet.size = rd + sizeof(Packet);
pn->packet.cksum = 0;
pn->packet.cksum = ~checksum(&pn->packet, pn->packet.size);
if ( rd == chunksize )
pn = pn->next = allocPacketNode(chunksize);
}
return head;
}
int checksum(unsigned char * data, int len)
{
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
if ( sum > 0xffff )
sum = (sum & 0xffff) + (sum>>16);
return sum;
}
void test( PacketNode * ptr ) {
FILE *fpNew = fopen("test.jpg", "w");
while (ptr != NULL)
{
printf("sequence: %d/%d, checksum: %04x, size: %d\n",
ptr->packet.seq,
ptr->packet.maxseq,
ptr->packet.cksum,
ptr->packet.size - sizeof(Packet)
);
int b = fwrite(ptr->packet.payload, ptr->packet.size - sizeof(Packet), 1, fpNew);
ptr = ptr->next;
}
fclose(fpNew);
}
void fatal( const char * msg ) { printf("FATAL: %s\n", msg); exit(1); }
int main(int argc, char** argv)
{
if ( ! argv[1] ) fatal( "missing filename argument" );
FILE * fp = fopen( argv[1], "r" );
if ( ! fp ) fatal( "cannot open file" );
fseek( fp, 0, SEEK_END );
long fsize = ftell(fp);
fseek( fp, 0, SEEK_SET );
printf("Filesize: %d\n", fsize );
test( prepare(fp, fsize, 1024) );
}
The #pragma push(pack,1) changes how the compiler aligns fields of the struct. We want them to be compact, for network transport. Using 1 is byte-aligned. The #pragma pop(pack) restores the previous setting of the pack pragma.
A note on the checksum method
First we calculate the sum of all the bytes in the packet:
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
Since the packet uses an unsigned short (16 bits, max value 65535 or 0xffff) to store the checksum, we make sure that the result will fit:
if ( sum > 0xffff ) // takes up more than 16 bits.
Getting the low 16 bits of this int is done using sum & 0xffff, masking out everything but the low 16 bits. We could simply return this value, but we would loose the information from higher checksum bits. So, we will add the upper 16 bits to the lower 16 bits. Accessing the higher 16 bits is done by shifting the int to the right 16 bits, like so: sum >> 16. This is the same as sum / 65536, since 65536 = 216 = 1 << 16.
sum = (sum & 0xffff) + (sum>>16); // add low 16 bits and high 16 bits
I should note that network packet checksums are usually computed 2 bytes (or 'octets' as they like to call them there) at a time. For that, the data should be cast to an unsigned short *, and len should be divided by 2. However! len may be odd, so in that case we'll need to take special care of the last byte. For instance, assuming that the maximum packet size is even, and that the len argument is always <= max_packet_size:
unsigned short * in = (unsigned short *) data;
if ( len & 1 ) data[len] = 0; // make sure last byte is 0
len = (len + 1) / 2;
The rest of the checksum method can remain the same, except that it should operate on in instead of data.