I'm writing a c program designed to transfer data over a socket to python client. I've encountered a really strange issue where writing to the created socket stops working with the addition of virtually any line of code after a certain point in the program.
To expand on the issue: I'm trying to write an arbitrary number to the socket, e.g. 256. This works fine, i.e. the python client receives the number 256 from the c server, as long as there aren't any commands beyond get_status(s2mm_status,"S2MM");
If there are any such commands beyond this point, the "0" gets written to the socket instead of whatever number (e.g. 256) I've specified. Anything as simple as the declaration "int i
" results in this behavior.
Needless to say, I'm confused. I'm wondering if I'm using too much memory or something? I just don't know how to diagnose the problem. Anyway, I've provided the code below. Sorry about the length, I just really don't know what is or is not relevant.
To provide a basic explanation of the code: a number of memory maps are created so that I can write specific values to registers, which initiates the recording of data from an ADC aboard the device, writing of this data to memory, and then passing this data over a socket to the python client.
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h>
#include<sys/socket.h>
#include<arpa/inet.h> // inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading, link with lpthread
#include<sys/mman.h>
#include <fcntl.h>
#include <arpa/inet.h> //https://linux.die.net/man/3/htonl
#include <time.h>
#include<math.h>
#include "server_library.h"
/*********************************/
//Address Editor
/*********************************/
//ps_0
// Data
// axi_dma_0 S_AXI_LITE reg 0x4040_0000 64K 0x4040_FFFF
//axi_dma_0
// Data_SG
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
// DATA_MM2S
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
// DATA_S2MM
// ps_0 S_AXI_HP0 HP0_DDR_LOWOCM 0x0800_0000 128M 0x07FF_FFFF
/*********************************/
/*********************************/
//Addresses
/*********************************/
#define AXI_DMA_ADDRESS 0x40400000
#define HP0_ADDRESS 0x08000000 //Formerly HP0_DMA_BUFFER_MEM_ADDRESS
#define MM2S_BASE_DESC_ADDR HP0_ADDRESS //Formerly HP0_MM2S_DMA_DESCRIPTORS_ADDRESS
#define S2MM_BASE_DESC_ADDR HP0_ADDRESS+MEMBLOCK_WIDTH+1 //Formerly HP0_S2MM_DMA_DESCRIPTORS_ADDRESS
#define MM2S_SOURCE_ADDRESS HP0_ADDRESS+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_MM2S_SOURCE_MEM_ADDRESS
#define S2MM_TARGET_ADDRESS HP0_ADDRESS+(MEMBLOCK_WIDTH+1)+SG_DMA_DESCRIPTORS_WIDTH+1 //Formerly HP0_S2MM_TARGET_MEM_ADDRESS
// AXI_DMA_ADDRESS: 0x40400000
// HP0_ADDRESS: 0x08000000
// MM2S_BASE_DESC_ADDR: 0x08000000
// S2MM_BASE_DESC_ADDR: 0x0c000000
// MM2S_SOURCE_ADDRESS: 0x08010000
// S2MM_TARGET_ADDRESS: 0x0c010000
/*********************************/
//Miscellaneous
/*********************************/
#define DESCRIPTOR_REGISTERS_SIZE 0xFFFF
#define SG_DMA_DESCRIPTORS_WIDTH 0xFFFF
#define MEMBLOCK_WIDTH 0x3FFFFFF //Size of memory used by S2MM and MM2S
#define BUFFER_BLOCK_WIDTH 0x7D0000 //Size of memory block per descriptor in bytes
#define NUM_OF_DESCRIPTORS 0x02 //Number of descriptors for each direction
#define START_FRAME 0x08000000 //TXSOF = 1 TXEOF = 0
#define MID_FRAME 0x00000000 //TXSOF = TXEOF = 0
#define COMPLETE_FRAME 0x0C000000 //TXSOF = TXEOF = 1
#define END_FRAME 0x04000000 //TXSOF = 0 TXEOF = 1
#define CYCLIC_ENABLE 0x10
#define TRANSFER_BYTES 1024
#define TRANSFER_INTS 256
#define TRANSFER_BITS 8*TRANSFER_BYTES
#define N_DESC 2
/*********************************/
//Offsets
/*********************************/
// MM2S CONTROL
#define MM2S_CONTROL_REGISTER 0x00 // MM2S_DMACR
#define MM2S_STATUS_REGISTER 0x04 // MM2S_DMASR
#define MM2S_CURDESC 0x08 // must align 0x40 addresses
#define MM2S_CURDESC_MSB 0x0C // unused with 32bit addresses
#define MM2S_TAILDESC 0x10 // must align 0x40 addresses
#define MM2S_TAILDESC_MSB 0x14 // unused with 32bit addresses
#define SG_CTL 0x2C // CACHE CONTROL
// S2MM CONTROL
#define S2MM_CONTROL_REGISTER 0x30 // S2MM_DMACR
#define S2MM_STATUS_REGISTER 0x34 // S2MM_DMASR
#define S2MM_CURDESC 0x38 // must align 0x40 addresses
#define S2MM_CURDESC_MSB 0x3C // unused with 32bit addresses
#define S2MM_TAILDESC 0x40 // must align 0x40 addresses
#define S2MM_TAILDESC_MSB 0x44 // unused with 32bit addresses
//Scatter/Gather Control
#define NEXT_DESC 0x00 //Set to address of next descriptor in chain
#define BUFF_ADDR 0x08 //Set to address to read from (MM2S) or write to (S2MM)
#define CONTROL 0x18 //Set transfer length, T/RXSOF and T/RXEOF
#define STATUS 0x1C //Descriptor status
/*********************************/
//Functions
/*********************************/
unsigned int set_offset(unsigned int* virtual_address, int offset, unsigned int value){
virtual_address[offset>>2] = value;
}
unsigned int get_offset(unsigned int* virtual_address, int offset) {
return virtual_address[offset>>2];
}
void print_offset(unsigned int* virtual_address, int offset){
unsigned int value = get_offset(virtual_address,offset);
printf("0x%08x\n",value);
}
void memsend(void* virtual_address, int byte_count, int socket_desc)
{
unsigned int *p = virtual_address;
int offset;
for(offset = 0; offset<byte_count;offset++){
printf("0x%08x\n",p[offset]);
write(socket_desc,&p[offset],sizeof(p[offset]));
}
}
void memdump(void* virtual_address, int byte_count)
{
unsigned int *p = virtual_address;
int offset;
for(offset = 0; offset<byte_count;offset++){
printf("%d: 0x%08x\n",offset,p[offset]);
}
}
void get_status(uint32_t status, char *type){
if(type == "S2MM"){
printf("S2MM status 0x%08x @0x%08x\n",status,AXI_DMA_ADDRESS+S2MM_STATUS_REGISTER);
}
if(type == "MM2S"){
printf("MM2S status 0x%08x @0x%08x\n",status,AXI_DMA_ADDRESS+MM2S_STATUS_REGISTER);
}
if(status & 0x00000001) printf(" Halted");
if(status & 0x00000002) printf(" Idle");
if(status & 0x00000008) printf(" SGIncld");
if(status & 0x00000010) printf(" DMAIntErr");
if(status & 0x00000020) printf(" DMASlvErr");
if(status & 0x00000040) printf(" DMADecErr");
if(status & 0x00000100) printf(" SGIntErr");
if(status & 0x00000200) printf(" SGSlvErr");
if(status & 0x00000400) printf(" SGDecErr");
if(status & 0x00001000) printf(" IOC_Irq");
if(status & 0x00002000) printf(" Dly_Irq");
if(status & 0x00004000) printf(" Err_Irq");
else printf(" running");
printf("\n");
}
int main(){
int mm2s_status, s2mm_status;
uint32_t mm2s_base_descriptor_address; //Formerly mm2s_current_descriptor_address
uint32_t s2mm_base_descriptor_address; //Formerly s2mm_current_descriptor_address
uint32_t mm2s_tail_descriptor_address;
uint32_t s2mm_tail_descriptor_address;
int fd = open("/dev/mem",O_RDWR|O_SYNC);
//Create 64K AXI DMA Memory Map at AXI_DMA_ADDRESS (0x40400000)
unsigned int* axi_dma = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,AXI_DMA_ADDRESS);
//Create 64k mm2s descriptors memory map at HP0_MM2S_DMA_DESCRIPTORS_ADDRESS (0x08000000)
unsigned int* mm2s_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,MM2S_BASE_DESC_ADDR); //Formerly mm2s_descriptor_register_mmap
//Create 64k s2mm descriptors memory map at HP0_S2MM_DMA_DESCRIPTORS_ADDRESS (0x0c000000)
unsigned int* s2mm_descriptors = mmap(NULL,DESCRIPTOR_REGISTERS_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,S2MM_BASE_DESC_ADDR); //Formerly s2mm_descriptor_register_mmap
//Create ~1Mb x Num_Descriptors source memory map at HP0_MM2S_SOURCE_MEM_ADDRESS (0x08010000)
unsigned int* source_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(MM2S_SOURCE_ADDRESS)); //Formerly source_mmap
//Create ~1Mb x Num_Descriptors target memory map at HP0_S2MM_TARGET_MEM_ADDRESS (0x0c010000)
unsigned int* dest_memory = mmap(NULL,BUFFER_BLOCK_WIDTH*NUM_OF_DESCRIPTORS,PROT_READ|PROT_WRITE,MAP_SHARED,fd,(off_t)(S2MM_TARGET_ADDRESS)); //Formerly dest_mmap
//Clear mm2s descriptors
memset(mm2s_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE);
//Clear s2mm descriptors
memset(s2mm_descriptors,0x00000000,DESCRIPTOR_REGISTERS_SIZE);
//Clear Target Memory
memset(dest_memory,0x00000000,NUM_OF_DESCRIPTORS*BUFFER_BLOCK_WIDTH/4);
//Reset and halt all DMA operations
set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x4);
set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x4);
set_offset(axi_dma,MM2S_CONTROL_REGISTER,0x0);
set_offset(axi_dma,S2MM_CONTROL_REGISTER,0x0);
mm2s_status = get_offset(axi_dma,MM2S_STATUS_REGISTER);
s2mm_status = get_offset(axi_dma,S2MM_STATUS_REGISTER);
get_status(mm2s_status,"MM2S");
get_status(s2mm_status,"S2MM");
/*********************************************************************/
// Any code after this point, save for a print function,
// breaks the write function (line 223) below.
//Specifically, it goes from correctly writing TRANSFER_INTS = 256
//to writing 0 to "new_socket"
//????
/*********************************************************************/
/*********************************************************************/
// Open a server
/*********************************************************************/
//Define variables
int new_socket,c;
int socket_desc;
struct sockaddr_in created_server_addr, client_addr;
//Create Socket
socket_desc = open_socket(socket_desc);
//Create Server
created_server_addr = server_structure(created_server_addr);
//Bind Socket
bind_socket(socket_desc,created_server_addr);
//Listen
listen(socket_desc,3);
puts("Waiting for incoming connections...");
//Transfer Data over socket
while(new_socket=accept(socket_desc,(struct sockaddr *)&client_addr, (socklen_t*)&c))
{
puts("Connection Accepted.\n");
printf("Transfer Size: %d\n",TRANSFER_INTS);
uint32_t htonl_TRANSFER_INTS = htonl(TRANSFER_INTS);
write(new_socket, &htonl_TRANSFER_INTS,sizeof(htonl_TRANSFER_INTS));
printf("Write Data (Destination memory block): \n");
close(new_socket);
break;
}
close(socket_desc);
/*********************************************************************/
}
I'm also including the "server_library.h" file for reference, which I wrote ti simplify the process of starting a socket a little bit. I can provide the python client code on request, but I'm already worried this is way too much code to sift through already.
#ifndef MY_HEADER_H
#define MY_HEADER_H
//Start/open Socket
int open_socket(int socket_desc)
{
int option = 1;
socket_desc = socket(AF_INET,SOCK_STREAM,0);
if(socket_desc == -1)
{
printf("Could not create socket\n");
}
//This stupid line fixes binds failing
setsockopt(socket_desc,SOL_SOCKET,SO_REUSEADDR,(void *)&option,sizeof(option));
return socket_desc;
}
//Prepare server structure
struct sockaddr_in server_structure(struct sockaddr_in server_addr)
{
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(8888);
return server_addr;
}
//Bind Socket
void bind_socket(int socket_desc, struct sockaddr_in server_addr)
{
if(bind(socket_desc,(struct sockaddr *)&server_addr, sizeof(server_addr))<0)
{
puts("Bind Failed\n");
}else{
puts("Bind Done\n");
}
}
//Send Message (uint32_t)
//Doesn't Work I dunno why
void send_int(uint32_t message, int socket)
{
message = htonl(message);
write(socket, &message, sizeof(message));
}
#endif
I'm sorry to be so vague here and throw so much code out, I just don't even really have any ideas for how to diagnose this issue, let alone start narrowing the cause down.
Anyway, thank you for the help. I'm happy to provide as much additional information as I am able.
When changing the code in unrelated ways breaks a program, here are some things to check for: 1. Stack overflow (this is more common in firmware/embedded code on microprocessors, but can happen especially with recursion or if you put large arrays and such on the stack) 2. Wild pointers, out-of-bounds writes to arrays or strings, etc. which lead to a memory overwrite (changing the code in an unrelated way may change the memory layout such that the memory overwrite is in either a harmless or a harmful location) [Do you check that all the arrays you try to allocate are successfully allocated?] [uses of set_offset are candidates for out-of-bounds access]
That is where I would start.
And, of course, turning on compiler warnings and checking return values from all function calls that have them.
If you do all of the above, you will either find the bug, or you can give us information which will help us to help you better.
User contributions licensed under CC BY-SA 3.0