I am developing a FreeRTOS application on a Cortex-M4 (NXP i.MX8MM) that creates 4 tasks.
The first task is waiting to receive a character on a UART. As soon as a buffer is received, it is sent to task 3 with xQueueSend.
The second task is the transmission task via the UART. It waits permanently for the reception of a buffer (sent by task 4) with xQueueReceive.
Currently, I manage to create these 4 tasks, but only the first 2 are executed. I have the impression that the second task, and particularly the xQueueReceive function, is blocking (or not executing properly) the execution of the last 2 tasks. If I comment out the xQueueReceive function, all tasks run without any problem. All configASSERT in the xQueueReceive function pass without problem.
Where do you think this can come from?
My code:
main.c
/* System includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Kernel includes */
#include "FreeRTOS.h"
#include "task.h"
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "rsc_table.h"
/* Other includes */
#include "A_version.h"
#include "A_rpmsg.h"
#include "A_ip_task.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Globals
******************************************************************************/
/* Queue RPMSG -> UART RS-485 */
static QueueHandle_t rpmsg_to_uart_queue = NULL;
/* Queue RPMSG <- UART RS-485 */
static QueueHandle_t uart_to_rpmsg_queue = NULL;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/*!
* #brief Main function
*/
int main(void)
{
uint8_t status = 1;
/* Initialize standard SDK demo application pins */
/* Board specific RDC settings */
BOARD_RdcInit();
BOARD_InitBootPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitMemory();
copyResourceTable();
#ifdef MCMGR_USED
/* Initialize MCMGR before calling its API */
(void)MCMGR_Init();
#endif /* MCMGR_USED */
PRINTF("Start Appli_metier: %s\r\n", NUM_ET_DATE_VERSION_CARTE_CM);
/* Chargement des paramètres de l'UART */
F_ip_485_load_params();
/* Initialisation de l'UART */
status = F_init_ip_485();
/* Initialisation de RPMsg */
if(status != 0)
{
PRINTF("ERROR INIT UART\r\n");
} else {
status = rpmsg_init();
}
rpmsg_to_uart_queue = xQueueCreate(10, sizeof(struct Message *));
if (rpmsg_to_uart_queue != NULL)
{
vQueueAddToRegistry(rpmsg_to_uart_queue, "RPMsg to UART queue");
}
uart_to_rpmsg_queue = xQueueCreate(10, sizeof(struct Message *));
if (uart_to_rpmsg_queue != NULL)
{
vQueueAddToRegistry(uart_to_rpmsg_queue, "UART to RPMsg queue");
}
/* Lancement des taches */
if(status != 0)
{
PRINTF("ERROR INIT RPMSG\r\n");
} else {
PRINTF("Avant F_ip_485_task\r\n");
/* Lancement de la tache UART */
F_ip_485_task(rpmsg_to_uart_queue, uart_to_rpmsg_queue);
PRINTF("Avant rpmsg_task\r\n");
/* Lancement de la tache RPMSG (cote A53) */
rpmsg_task(rpmsg_to_uart_queue, uart_to_rpmsg_queue);
}
vTaskStartScheduler();
PRINTF("Failed to start FreeRTOS on core0.\n");
for (;;)
;
}
tasks 1 and 2:
#include "A_ip_task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "fsl_debug_console.h"
#include "A_ip_485.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define IP_485_RX_TASK_STACK_SIZE (256)
#define IP_485_TX_TASK_STACK_SIZE (256)
#define MAX_BUF_TRAME_ETHERNET 1520
/* Task priorities. */
#define hello_task_PRIORITY (configMAX_PRIORITIES - 1)
#define TASK_DELAY_IP_485 200
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
typedef struct _uart_struct
{
QueueHandle_t my_queue_to_uart;
QueueHandle_t my_queue_to_rpmsg;
} uart_struct;
static uart_struct my_uart_struct;
static TaskHandle_t ip_485_rx_task_handle = NULL;
static TaskHandle_t ip_485_tx_task_handle = NULL;
STRUCT_parametre_uart S_device_UART[NBR_MAX_UART];
unsigned char TUCH_ip_485_buffer[MAX_BUF_TRAME_ETHERNET];
static void F_ip_485_rx_task(void *pvParameters)
{
uart_struct * param_struct = pvParameters;
Message st_msg;
uint16_t UI_lg;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
PRINTF("\r\nF_ip_485_rx_task running ...\r\n");
/* On attend la réception d'une trame sur la file */
for (;;)
{
if ((UI_lg = F_driverUART_read(UART_IP485, TUCH_ip_485_buffer, MAX_BUF_TRAME_ETHERNET)) != 0)
{
//TODO: F_traitement_RX_IP_485(TUCH_ip_485_buffer, UI_lg); /* Traitement dans MQX */
/* Remplacer par écriture dans la queue de RPMsg pour envoi vers Cortex-A53 */
st_msg.size = UI_lg;
xQueueSend(param_struct->my_queue_to_rpmsg, (void *)&st_msg, 10);
}
vTaskDelay(xDelay);
}
vTaskSuspend(NULL);
}
static void F_ip_485_tx_task(void *pvParameters)
{
uart_struct * param_struct = pvParameters;
Message rcv_msg;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
PRINTF("\r\nF_ip_485_tx_task running ...\r\n");
for (;;)
{
if (xQueueReceive(param_struct->my_queue_to_uart, (void *)&rcv_msg, 0) != pdTRUE)
{
PRINTF("Failed to receive queue.\r\n");
}
else
{
/* On envoie tous les octets */
F_driverUART_IP485_write(rcv_msg.body, rcv_msg.size);
}
vTaskDelay(xDelay);
}
vTaskSuspend(NULL);
}
void F_ip_485_task(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
my_uart_struct.my_queue_to_uart = r_to_u;
my_uart_struct.my_queue_to_rpmsg = u_to_r;
if (xTaskCreate(F_ip_485_rx_task, "IP 485 RX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &ip_485_rx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
; }
if (xTaskCreate(F_ip_485_tx_task, "IP 485 TX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &ip_485_tx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
}
tasks 3 and 4:
#include "A_rpmsg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "rpmsg_lite.h"
#include "rpmsg_queue.h"
#include "rpmsg_ns.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define RPMSG_LITE_SHMEM_BASE (VDEV0_VRING_BASE)
#define RPMSG_LITE_LINK_ID (RL_PLATFORM_IMX8MM_M4_USER_LINK_ID)
#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-virtual-tty-channel-1"
#define RPMSG_RX_TASK_STACK_SIZE (128)
#define RPMSG_TX_TASK_STACK_SIZE (128)
#ifndef LOCAL_EPT_ADDR
#define LOCAL_EPT_ADDR (30)
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
typedef struct _rpmsg_struct
{
struct rpmsg_lite_endpoint *volatile my_ept;
volatile rpmsg_queue_handle my_queue;
struct rpmsg_lite_instance *volatile my_rpmsg;
QueueHandle_t my_queue_to_uart;
QueueHandle_t my_queue_to_rpmsg;
} rpmsg_struct;
static TaskHandle_t rpmsg_rx_task_handle = NULL;
static TaskHandle_t rpmsg_tx_task_handle = NULL;
static SemaphoreHandle_t mutex;
static rpmsg_struct my_rpmsg_struct;
static volatile uint32_t remote_addr;
static char app_rx_buf[1500]; /* Each RPMSG buffer can carry less than 512 payload */
static char app_tx_buf[1500]; /* Each RPMSG buffer can carry less than 512 payload */
static void rpmsg_rx_task(void *param)
{
rpmsg_struct * param_struct = param;
Message st_msg;
volatile uint32_t local_remote_addr;
void *rx_buf;
uint32_t len;
int32_t result;
void *tx_buf;
uint32_t size;
boolean init = false;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
for (;;)
{
/* Get RPMsg rx buffer with message */
result =
rpmsg_queue_recv_nocopy(param_struct->my_rpmsg, param_struct->my_queue, (uint32_t *)&remote_addr, (char **)&rx_buf, &len, RL_BLOCK);
if (result != 0)
{
assert(false);
} else {
PRINTF("RPMsg received !\r\n");
}
/* Copy string from RPMsg rx buffer */
assert(len < sizeof(app_rx_buf));
memcpy(st_msg.body, rx_buf, len);
st_msg.size = len;
xQueueSend(param_struct->my_queue_to_uart, (void *)&st_msg, 10);
//app_rx_buf[len] = 0; /* End string by '\0' */
if ((len == 2) && (app_rx_buf[0] == 0xd) && (app_rx_buf[1] == 0xa))
PRINTF("Get New Line From Master Side\r\n");
else
PRINTF("Get Message From Master Side : \"%s\" [len : %d]\r\n", app_rx_buf, len);
if(!init) {
local_remote_addr = remote_addr;
// Release the mutex so that the creating function can finish
xSemaphoreGive(mutex);
init = true;
}
/* Release held RPMsg rx buffer */
result = rpmsg_queue_nocopy_free(param_struct->my_rpmsg, rx_buf);
if (result != 0)
{
assert(false);
}
}
vTaskSuspend(NULL);
}
static void rpmsg_tx_task(void *param)
{
rpmsg_struct * param_struct = param;
Message rcv_msg;
volatile uint32_t local_remote_addr;
void *rx_buf;
uint32_t len;
int32_t result;
void *tx_buf;
uint32_t size;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
/* On attend de recevoir l'adresse de destination */
PRINTF("\r\nM4 waiting for destination address ...\r\n");
// Take the mutex
xSemaphoreTake(mutex, portMAX_DELAY);
local_remote_addr = remote_addr;
for (;;)
{
if (xQueueReceive(param_struct->my_queue_to_rpmsg, (void *)&rcv_msg, portMAX_DELAY) != pdTRUE)
{
PRINTF("Failed to receive queue.\r\n");
}
else
{
/* Get tx buffer from RPMsg */
tx_buf = rpmsg_lite_alloc_tx_buffer(param_struct->my_rpmsg, &size, RL_BLOCK);
assert(tx_buf);
/* Copy string to RPMsg tx buffer */
memcpy(tx_buf, rcv_msg.body, rcv_msg.size);
/* Echo back received message with nocopy send */
result = rpmsg_lite_send_nocopy(param_struct->my_rpmsg, param_struct->my_ept, local_remote_addr, tx_buf, rcv_msg.size);
if (result != 0)
{
assert(false);
} else {
PRINTF("RPMsg sent !\r\n");
}
}
}
vTaskSuspend(NULL);
}
uint8_t rpmsg_init(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
uint8_t status;
#ifdef MCMGR_USED
uint32_t startupData;
/* Get the startup data */
(void)MCMGR_GetStartupData(kMCMGR_Core1, &startupData);
my_rpmsg = rpmsg_lite_remote_init((void *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
/* Signal the other core we are ready */
(void)MCMGR_SignalReady(kMCMGR_Core1);
#else
my_rpmsg_struct.my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
#endif /* MCMGR_USED */
PRINTF("En attente du chargement du module RPMsg...\r\n");
while (0 == rpmsg_lite_is_link_up(my_rpmsg_struct.my_rpmsg))
;
my_rpmsg_struct.my_queue = rpmsg_queue_create(my_rpmsg_struct.my_rpmsg);
my_rpmsg_struct.my_ept = rpmsg_lite_create_ept(my_rpmsg_struct.my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_rpmsg_struct.my_queue);
(void)rpmsg_ns_announce(my_rpmsg_struct.my_rpmsg, my_rpmsg_struct.my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, RL_NS_CREATE);
PRINTF("\r\nNameservice sent, ready for incoming messages...\r\n");
// Create mutex before starting tasks
mutex = xSemaphoreCreateMutex();
// Take the mutex
if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
{
status = 0;
} else {
status = -1;
}
return status;
}
void rpmsg_task(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
my_rpmsg_struct.my_queue_to_uart = r_to_u;
my_rpmsg_struct.my_queue_to_rpmsg = u_to_r;
if (xTaskCreate(rpmsg_rx_task, "RPMSG RX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &rpmsg_rx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
if (xTaskCreate(rpmsg_tx_task, "RPMSG TX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &rpmsg_tx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
}
Related
I'm building a modbus tcp server on top of lwip, as the title says using the raw api since i'm using a bare metal system, as of today i have the application running, however when i poll too fast (lets say 1ms) the application crashes within 100 polls, if i lower the polling rate it still happens, just later on, in the serial debug i get
mem_free: illegal memory: non-linked: double freemem_free: illegal memory: non-linked: double free
the message is clear in what's happening, i'm having serious issues however tracking it down, i set a breakpoint where the message is produced and this is the call stack i get
> mem_free (void * rmem) Line: 717
pbuf_free (struct pbuf * p) Line: 780
tcp_seg_free (struct tcp_seg * seg) Line: 1631
tcp_segs_free (struct tcp_seg * seg) Line: 1616
tcp_pcb_purge (struct tcp_pcb * pcb, struct tcp_pcb * pcb#entry) Line: 2169
tcp_pcb_purge (struct tcp_pcb * pcb) Line: 2139
tcp_pcb_remove (struct tcp_pcb ** pcblist, struct tcp_pcb * pcb, struct tcp_pcb * pcb#entry) Line: 2191
tcp_input (struct pbuf * p, struct pbuf * p#entry, struct netif * inp, struct netif * inp#entry) Line: 448
ip4_input (struct pbuf * p, struct pbuf * p#entry, struct netif * inp, struct netif * inp#entry) Line: 709
ethernet_input (struct pbuf * p, struct netif * netif) Line: 186
ethernetif_input (struct netif * netif) Line: 788
ethernet_task Line: 247
main Line: 929
Interestingly this seems to happen not on the application but on the ip layer when removing a pcb, i really don't know the lwip code good enough to adequately debug this
after the double free issue the interface stops responding
right now im using the following lwipopts
* lwipopts.h
*
* Created: 11/10/2017 13:10:59
* Author: diego
*/
#define NO_SYS 1
#define LWIP_TIMERS 1
//#define NO_SYS_NO_TIMERS 1
#define MEM_ALIGNMENT 4
#define MEM_SIZE (28*1024)
#define TCP_MSS 1460
#define TCP_SND_BUF (7*TCP_MSS)
#define TCP_WND (7*TCP_MSS)
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
#define MEMP_NUM_PBUF 16
#define MEMP_NUM_TCP_PCB 10
#define PBUF_POOL_SIZE 28
//Checksum handled by hardware
#define CHECKSUM_GEN_IP 0
#define CHECKSUM_GEN_UDP 0
#define CHECKSUM_GEN_TCP 0
#define CHECKSUM_GEN_ICMP 0
#define CHECKSUM_CHECK_IP 0
#define CHECKSUM_CHECK_UDP 0
#define CHECKSUM_CHECK_TCP 0
#define CHECKSUM_CHECK_ICMP 0
#define LWIP_DHCP 1
#define LWIP_AUTOIP 1
#define LWIP_DHCP_AUTOIP_COOP 1
#define LWIP_DHCP_AUTOIP_COOP_TRIES 5
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETIF_API 0
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_SOCKET 0
#define LWIP_NETCONN 0
#define SO_REUSE 1
#define LWIP_IGMP 1
//#include <stmlib/rand.h>
//#define LWIP_RAND rand_value
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
extern int printf(const char *format, ...);
#define LWIP_PLATFORM_DIAG(x) {printf x;}
#define LWIP_DEBUG
#define LWIP_NOASSERT
#define LWIP_DBG_TYPES_ON (LWIP_DBG_STATE | LWIP_DBG_ON)
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#define AUTOIP_DEBUG LWIP_DBG_OFF
#define IGMP_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_LEVEL_SERIOUS
#define MEM_DEBUG LWIP_DBG_LEVEL_SERIOUS
#define SIMPLE_DISCOVERY_DEBUG LWIP_DBG_LEVEL_SERIOUS
#define TCP_TMR_INTERVAL 10
the checksums are disabled since the phy already takes care of that
this is the .h of the lwip app
#define MODBUSTCP_H_
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "../CONTROL_CONCURRENCIA/queue.h"
#include "../MEM_MGT/mempools.h"
#define MTCP_MAX_RETRIES 10
#define MTCP_QUEUE modbusTcpQueue
#define MTCP_QUEUE_BUF *mQueueBuffer[18]
#define MTCP_MEMP modbusTcpMemp
#ifndef MTCP_MAX_CONNS
#define MTCP_MAX_CONNS 5
#endif
extern queue_t MTCP_QUEUE;
extern void MTCP_QUEUE_BUF;
extern mempool_config MTCP_MEMP;
enum conn_status
{
MB_NONE = 0,
MB_CONNECTED,
MB_WAIT_TO_CLOSE,
MB_CLOSING
};
typedef struct
{
uint16_t transactionId;
uint16_t protocol;
uint16_t len;
uint8_t unitId;
} mbTcp_mbapHeader;
#define MBAP_PROTO_MB 0
typedef struct
{
uint8_t estado;
uint8_t retries;
struct tcp_pcb *pcb;
uint8_t *sendP;
uint8_t sendLen;
} mbTcp_status;
void modbusTcpStart(uint16_t port);
void modbusTcpStop(void);
err_t modbusTcpAccept(void *arg, struct tcp_pcb *pcb, err_t err);
err_t modbusTcpRecv(void *arg, struct tcp_pcb *mPcb, struct pbuf *p, err_t err);
void modbusTcpError(void *arg, err_t err);
err_t modbusTcpPoll(void *arg, struct tcp_pcb *mPcb);
void modbusTcpSend(struct tcp_pcb *mPcb, mbTcp_status *mbStatus);
err_t modbusTcpSent(void *arg, struct tcp_pcb *pcb, u16_t len);
void modbusTcpClose(struct tcp_pcb *pcb, mbTcp_status *mbStatus);
uint16_t swapBytes(uint8_t *ptr);
extern uint8_t mTcpCallGood(mbTcp_status *status, struct pbuf *p, mbTcp_mbapHeader hdr);
and this is the lwip app .cfile
/*
* modbusTcp.c
*
* Created: 19/08/2019 14:05:11
* Author: diego
*/
#include "modbusTcp.h"
uint8_t actConns = 0;
uint16_t swapBytes(uint8_t *ptr)
{
uint16_t out = ((uint16_t) * (ptr + 1)) | ((uint16_t) * (ptr) << 8);
return out;
}
void modbusTcpStart(uint16_t port)
{
volatile err_t err;
struct tcp_pcb *pcb;
pcb = tcp_new();
//LWIP_ASSERT("falla al crear el pcb de modbus tcp", pcb != NULL);
if(pcb != NULL)
{
err = tcp_bind(pcb, IP_ADDR_ANY, port);
//tcp_setprio(pcb, MODBUS_TCP_PRIO);
//LWIP_ASSERT("Falla al iniciar modbus TCP (bind)", err == ERR_OK);
if(err == ERR_OK)
{
pcb = tcp_listen(pcb);
//LWIP_ASSERT("Falla al iniciar modbus TCP (listen)", err == ERR_OK);
tcp_accept(pcb, modbusTcpAccept);
return;
}
}
else
return;
}
err_t modbusTcpAccept(void *arg, struct tcp_pcb *mPcb, err_t err)
{
err_t ret_err;
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
if(actConns >= MTCP_MAX_CONNS)
{
return ERR_MEM;
}
else
{
actConns++;
}
tcp_setprio(mPcb, TCP_PRIO_MAX);
mbStatus = (mbTcp_status *)mem_malloc(sizeof(mbTcp_status));
if(mbStatus != NULL)
{
mbStatus->estado = MB_CONNECTED;
mbStatus->pcb = mPcb;
mbStatus->retries = 0;
mbStatus->sendP = NULL;
/* pass newly allocated es to our callbacks */
tcp_arg(mPcb, mbStatus);
tcp_recv(mPcb, modbusTcpRecv);
tcp_err(mPcb, modbusTcpError);
tcp_poll(mPcb, modbusTcpPoll, 0);
ret_err = ERR_OK;
}
else
{
ret_err = ERR_MEM;
}
return ret_err;
}
err_t modbusTcpRecv(void *arg, struct tcp_pcb *mPcb, struct pbuf *p, err_t err)
{
mbTcp_status *mbStatus;
volatile mbTcp_mbapHeader headerTmp;
mbStatus = (mbTcp_status *)arg;
uint8_t *payloadPtr = (uint8_t *) p->payload;
//tcp_output(mPcb);
if(p == NULL)
{
if(mbStatus->sendP == NULL)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
else
{
mbStatus->estado = MB_WAIT_TO_CLOSE;
//pbuf_free(p);
}
// esto es que queda algo para procesar en la cola
// la conexion se cerrara luego de que se procesen los que quedan
// simplemente se descarta el entrante
}
else
{
// queda algo para mandar
// asi que lo mandamos
tcp_sent(mPcb, modbusTcpSent);
//modbusTcpSend(mPcb, mbStatus);
}
}
else
if(err != ERR_OK)
{
mbStatus->sendP = NULL;
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return err;
}
else
{
switch(mbStatus->estado)
{
case MB_CONNECTED:
if(p->len == 0)
{
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
break;
}
headerTmp.transactionId = swapBytes(payloadPtr);
headerTmp.protocol = swapBytes(payloadPtr + 2);
headerTmp.len = swapBytes(payloadPtr + 4);
headerTmp.unitId = *(payloadPtr + 6);
if(mTcpCallGood(mbStatus, p, headerTmp) != 0)
{
if(p != NULL)
{
pbuf_free(p);
}
tcp_recved(mPcb, p->tot_len);
break;
}
// asumimos que los chequeos y demas fueron realizados por el stack
break;
case MB_WAIT_TO_CLOSE:
// notese que no ponemos mbStatus->p a NULL
tcp_recved(mPcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
break;
case MB_CLOSING:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
default:
tcp_recved(mPcb, p->tot_len);
mbStatus->sendP = NULL;
pbuf_free(p);
return ERR_OK;
break;
}
}
}
void modbusTcpError(void *arg, err_t err)
{
mbTcp_status *mbStatus;
LWIP_UNUSED_ARG(err);
mbStatus = (mbTcp_status *)arg;
tcp_arg(mbStatus->pcb, NULL);
tcp_sent(mbStatus->pcb, NULL);
tcp_recv(mbStatus->pcb, NULL);
tcp_err(mbStatus->pcb, NULL);
tcp_poll(mbStatus->pcb, NULL, 0);
tcp_close(mbStatus->pcb);
/*if(mbStatus != NULL)
{
mem_free(mbStatus);
}*/
}
void modbusTcpSend(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
err_t wr_err = ERR_OK;
while((wr_err == ERR_OK) &&
(mbStatus->sendP != NULL) &&
(mbStatus->sendLen <= tcp_sndbuf(mPcb))
)
{
wr_err = tcp_write(mPcb, mbStatus->sendP, mbStatus->sendLen, 1);
if(wr_err == ERR_OK)
{
mbStatus->sendLen = 0;
break;
}
else
if(wr_err == ERR_MEM)
{
// por ahora simplemente no mandamos nada
// idealmente seria defer to poll
}
}
return;
}
err_t modbusTcpPoll(void *arg, struct tcp_pcb *mPcb)
{
}
void modbusTcpClose(struct tcp_pcb *mPcb, mbTcp_status *mbStatus)
{
tcp_arg(mPcb, NULL);
tcp_sent(mPcb, NULL);
tcp_recv(mPcb, NULL);
tcp_err(mPcb, NULL);
tcp_poll(mPcb, NULL, 0);
if(mbStatus != NULL)
{
mem_free(mbStatus);
}
tcp_close(mPcb);
actConns--;
}
err_t modbusTcpSent(void *arg, struct tcp_pcb *mPcb, u16_t len)
{
mbTcp_status *mbStatus;
mbStatus = (mbTcp_status *)arg;
LWIP_UNUSED_ARG(len);
mbStatus->retries = 0;
if(mbStatus->estado == MB_WAIT_TO_CLOSE)
{
if(getQueueLength(&MTCP_QUEUE) == 0)
{
// no quedan respuestas para mandar
// ni bloques que procesar
modbusTcpClose(mPcb, (mbTcp_status *)arg);
}
}
// no quedan respuestas para mandar
// y ya no habia nada en la cola
if(mbStatus->estado == MB_CLOSING)
{
modbusTcpClose(mPcb, mbStatus);
}
return ERR_OK;
}
this is the code that actually handles the queued packets
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
#define MBTCP_CALL_GOOD mTcpCallGood
#include "modbusTcp.h"
void initModbusTcpBalanza(void);
void modbusTcpParser(void);
extern MB_DBlock_t modbusDataBlock;
queue_t modbusTcpQueue;
mempool_config modbusTcpMemp;
void *mQueueBuffer[18];
uint8_t packet_buffer[260];
typedef struct
{
struct pbuf *p;
mbTcp_mbapHeader header;
MB_pdu pdu;
mbTcp_status *connStat;
} modbusTcpQueueElement;
#define MBTCP_POOL_SZ (sizeof(modbusTcpQueueElement)+36)*18
uint8_t mbTcpPoolBuffer[MBTCP_POOL_SZ];
uint8_t mTcpCallGood(mbTcp_status *status, struct pbuf *p, mbTcp_mbapHeader hdr)
{
modbusTcpQueueElement *queueElement;
if(hdr.len > 253)
{
return 2;
}
else
if(pool_allocate(&modbusTcpMemp, (uint8_t **)&queueElement) != 0)
{
queueElement->header = hdr;
queueElement->p = p;
queueElement->pdu.pduData = (uint8_t *) & (p->payload[7]);
queueElement->pdu.dataLen = hdr.len - 1;
queueElement->connStat = status;
if(enQueue(&modbusTcpQueue, queueElement) == -1)
{
while(true);
}
return 0;
}
else
return 1;
}
void modbusTcpParser(void)
{
//Disable_global_interrupt();
struct pbuf *p;
uint8_t parseRet;
if(getQueueLength(&modbusTcpQueue) > 0)
{
modbusTcpQueueElement *queueElement;
queueGetNext(&modbusTcpQueue, (void **)&queueElement);
uint8_t *mbapPtr = (uint8_t *) & (queueElement->header);
//delay_ms(1);
// copiamos a un buffer que sabemos tiene lugar
for(uint8_t i = 0; i < queueElement->pdu.dataLen; i++)
{
packet_buffer[i + 7] = queueElement->pdu.pduData[i];
}
tcp_recved(queueElement->connStat->pcb, queueElement->p->tot_len);
pbuf_free(queueElement->p);
queueElement->pdu.pduData = &packet_buffer[7];
switch(parseRet = parseModbusPdu(&(queueElement->pdu), modbusDataBlock))
{
case ERRCODE_PARSE_FAIL_NR:
break;
case ERRCODE_PARSE_OK:
case ERRCODE_ILL_DATA_ADDR:
case ERRCODE_ILL_FUNCTION:
queueElement->header.len = queueElement->pdu.dataLen;
packet_buffer[0] = mbapPtr[1];
packet_buffer[1] = mbapPtr[0];
packet_buffer[2] = mbapPtr[3];
packet_buffer[3] = mbapPtr[2];
packet_buffer[4] = mbapPtr[5];
packet_buffer[5] = mbapPtr[4];
packet_buffer[6] = mbapPtr[6];
queueElement->connStat->sendP = packet_buffer;
queueElement->connStat->sendLen = 7 + queueElement->pdu.dataLen;
modbusTcpSend(queueElement->connStat->pcb, queueElement->connStat);
//mb_232_resp(queueElement->port, queueElement->pdu.dataLen);
break;
default:
tcp_recved(queueElement->connStat->pcb, queueElement->p->tot_len);
pbuf_free(queueElement->p);
break;
}
// ojo, bloquear las interrupciones aca es muy importante
// llegaba a pasar que eliminaba de la cola pero no liberaba el elemento
Disable_global_interrupt();
pool_free(&modbusTcpMemp, (uint8_t *)queueElement);
deQueue(&modbusTcpQueue);
Enable_global_interrupt();
}
//Enable_global_interrupt();
return;
}
void initModbusTcp(void)
{
init_pool(&modbusTcpMemp, MBTCP_POOL_SZ, sizeof(modbusTcpQueueElement) + 36, mbTcpPoolBuffer);
queue_init((void **)mQueueBuffer, 18, &modbusTcpQueue);
}
Any help or leads are very appreciated
Pd: I know this code needs a lot of improvements and formatting, yet this is my first lwip app, and i need to get to a reasonable operating level relatively fast, so tidyness and order will be left for a bit later
I'm trying to build an application in contiki3.0 where several nodes broadcast their sensor data while writing it in a log and then every 3 min send the log to a sink and start a new log.
I also want the sink to acknowledge receiving the log.
I've been trying to do that for a month but I couldn't get the code to work properly, I would appreciate any help.
This is the code of the nodes:
#include "contiki-conf.h"
#include "dev/button-sensor.h"
#include "dev/light-sensor.h"
#include "dev/leds.h"
#include "net/linkaddr.h"
#include "contiki.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "event-post.h"
#include "simple-udp.h"
#include <limits.h>
#include <stdio.h>
#include <string.h>
#define UDP_PORT 1234
#define SEND_INTERVAL (20 * CLOCK_SECOND)
#define SEND_TIME (random_rand() % (SEND_INTERVAL))
/*---------------------------------------------------------------------------*/
static struct simple_udp_connection broadcast_connection;
static process_event_t event_data_ready;
/*---------------------------------------------------------------------------*/
PROCESS(sara, "broadcast");
PROCESS(broadcast_example_process, "BB");
AUTOSTART_PROCESSES(&sara, &broadcast_example_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sara, ev, data)
{
static struct etimer timer;
static struct event_struct es;
PROCESS_BEGIN();
es.s_val = SHRT_MAX-2;
es.i_val = INT_MAX-2;
es.l_val = LONG_MAX-2;
/* sizeof(long long) == sizeof(long) on sensinodes - see other examples*/
es.ll_val = LONG_MAX-2;
/* and some typedef-ed unsigned variables */
es.u8_val = UCHAR_MAX-2;
es.u16_val = USHRT_MAX-2;
es.u32_val = ULONG_MAX-2;
event_data_ready = process_alloc_event();
printf("Contiki allocated event ID %d.\r\n", event_data_ready);
etimer_set(&timer, CLOCK_CONF_SECOND * 2);
while(1){
printf("Sensor process: Wait for timer event...\r\n");
/* Wait on our timer */
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);
/* blip */
/* leds_toggle(LEDS_BLUE); */
/* Set the 'sensor' value before throwing the event */
printf("Sensor Process: Incrementing values...%d,%d,%d,%d,%d,%d, %d\r\n", es.s_val++, es.i_val++, es.l_val++, es.ll_val++, es.u8_val++, es.u16_val++,es.u32_val++);
/* Post our event.
* N.B. es is declared static.
* Try passing a volatile variable and observe the results... */
printf("Sensor Process: Generating 'Data Ready' event.\r\n");
process_post(&broadcast_example_process, event_data_ready, &es);
/* reset the timer so we can wait on it again */
etimer_reset(&timer);
}
SENSORS_ACTIVATE(button_sensor);
SENSORS_ACTIVATE(light_sensor);
static int counter=0;
printf("Light: \%u\n", light_sensor);
counter++;
if (counter == 4){
printf("Hello, world you have read the light 4 times \n");
}
PROCESS_END();
}
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received on port %d from port %d with length %d\n",
receiver_port, sender_port, datalen);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
static struct etimer periodic_timer;
static struct etimer send_timer;
uip_ipaddr_t addr;
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, UDP_PORT,
NULL, UDP_PORT,
receiver);
etimer_set(&periodic_timer, SEND_INTERVAL);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
etimer_reset(&periodic_timer);
etimer_set(&send_timer, SEND_TIME);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer));
printf("Sending broadcast\n");
uip_create_linklocal_allnodes_mcast(&addr);
simple_udp_sendto(&broadcast_connection, data, sizeof(data), &addr);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
and this is the sink code, which is a udp-sink code from Contiki examples:
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/rpl/rpl.h"
#include "net/linkaddr.h"
#include "net/netstack.h"
#include "dev/button-sensor.h"
#include "dev/serial-line.h"
#if CONTIKI_TARGET_Z1
#include "dev/uart0.h"
#else
#include "dev/uart1.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "collect-common.h"
#include "collect-view.h"
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UDP_CLIENT_PORT 8775
#define UDP_SERVER_PORT 5688
static struct uip_udp_conn *server_conn;
PROCESS(udp_server_process, "UDP server process");
AUTOSTART_PROCESSES(&udp_server_process,&collect_common_process);
/*---------------------------------------------------------------------------*/
void
collect_common_set_sink(void)
{
}
/*---------------------------------------------------------------------------*/
void
collect_common_net_print(void)
{
printf("I am sink!\n");
}
/*---------------------------------------------------------------------------*/
void
collect_common_send(void)
{
/* Server never sends */
}
/*---------------------------------------------------------------------------*/
void
collect_common_net_init(void)
{
#if CONTIKI_TARGET_Z1
uart0_set_input(serial_line_input_byte);
#else
uart1_set_input(serial_line_input_byte);
#endif
serial_line_init();
PRINTF("I am sink!\n");
}
/*---------------------------------------------------------------------------*/
static void
tcpip_handler(void)
{
uint8_t *appdata;
linkaddr_t sender;
uint8_t seqno;
uint8_t hops;
if(uip_newdata()) {
appdata = (uint8_t *)uip_appdata;
sender.u8[0] = UIP_IP_BUF->srcipaddr.u8[15];
sender.u8[1] = UIP_IP_BUF->srcipaddr.u8[14];
seqno = *appdata;
hops = uip_ds6_if.cur_hop_limit - UIP_IP_BUF->ttl + 1;
collect_common_recv(&sender, seqno, hops,
appdata + 2, uip_datalen() - 2);
}
}
/*---------------------------------------------------------------------------*/
static void
print_local_addresses(void)
{
int i;
uint8_t state;
PRINTF("Server IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) {
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
PRINTF("\n");
/* hack to make address "final" */
if (state == ADDR_TENTATIVE) {
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
}
}
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(udp_server_process, ev, data)
{
uip_ipaddr_t ipaddr;
struct uip_ds6_addr *root_if;
PROCESS_BEGIN();
PROCESS_PAUSE();
SENSORS_ACTIVATE(button_sensor);
PRINTF("UDP server started\n");
#if UIP_CONF_ROUTER
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 1);
/* uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); */
uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
root_if = uip_ds6_addr_lookup(&ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr);
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
#endif /* UIP_CONF_ROUTER */
print_local_addresses();
/* The data sink runs with a 100% duty cycle in order to ensure high
packet reception rates. */
NETSTACK_RDC.off(1);
server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL);
udp_bind(server_conn, UIP_HTONS(UDP_SERVER_PORT));
PRINTF("Created a server connection with remote address ");
PRINT6ADDR(&server_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n", UIP_HTONS(server_conn->lport),
UIP_HTONS(server_conn->rport));
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
tcpip_handler();
} else if (ev == sensors_event && data == &button_sensor) {
PRINTF("Initiaing global repair\n");
rpl_repair_root(RPL_DEFAULT_INSTANCE);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
Trying to create a raw socket based program using mmap_packet to send packets at fast rate.
The following code is adopted from the example at this gist. It does send packets but it doesn't send it fast. On my 1Gbps nic (r8169 driver), it only sends at a rate of about 95,000 packets/second on my corei7 processor (3.1GHz). I believe it could have sent at much higher rate.
Not sure what is the bottleneck. Any ideas? Thanks!
Here is the code snippet:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <sys/time.h>
#define PACKET_QDISC_BYPASS 20
/// The number of frames in the ring
// This number is not set in stone. Nor are block_size, block_nr or frame_size
#define CONF_RING_FRAMES 1024
#define CONF_DEVICE "eth0"
/// Offset of data from start of frame
#define PKT_OFFSET (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + \
TPACKET_ALIGN(sizeof(struct sockaddr_ll)))
/// (unimportant) macro for loud failure
#define RETURN_ERROR(lvl, msg) \
do { \
fprintf(stderr, msg); \
return lvl; \
} while(0);
static struct sockaddr_ll txring_daddr;
double getTS() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec/1000000.0;
}
/// create a linklayer destination address
// #param ringdev is a link layer device name, such as "eth0"
static int
init_ring_daddr(int fd, const char *ringdev)
{
struct ifreq ifreq;
// get device index
strcpy(ifreq.ifr_name, ringdev);
if (ioctl(fd, SIOCGIFINDEX, &ifreq)) {
perror("ioctl");
return -1;
}
txring_daddr.sll_family = AF_PACKET;
txring_daddr.sll_protocol = htons(ETH_P_IP);
txring_daddr.sll_ifindex = ifreq.ifr_ifindex;
// set the linklayer destination address
// NOTE: this should be a real address, not ff.ff....
txring_daddr.sll_halen = ETH_ALEN;
memset(&txring_daddr.sll_addr, 0xff, ETH_ALEN);
return 0;
}
/// Initialize a packet socket ring buffer
// #param ringtype is one of PACKET_RX_RING or PACKET_TX_RING
static char *
init_packetsock_ring(int fd, int ringtype)
{
struct tpacket_req tp;
char *ring;
// tell kernel to export data through mmap()ped ring
tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
tp.tp_block_nr = 1;
tp.tp_frame_size = getpagesize();
tp.tp_frame_nr = CONF_RING_FRAMES;
if (setsockopt(fd, SOL_PACKET, ringtype, (void*) &tp, sizeof(tp))) {
perror("setting up ring");
RETURN_ERROR(NULL, "setsockopt() ring\n");
}
#ifdef TPACKET_V2
printf("it's TPACKET_V2\n");
val = TPACKET_V1;
setsockopt(fd, SOL_PACKET, PACKET_HDRLEN, &val, sizeof(val));
#endif
// open ring
ring = mmap(0, tp.tp_block_size * tp.tp_block_nr,
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (!ring)
RETURN_ERROR(NULL, "mmap()\n");
if (init_ring_daddr(fd, CONF_DEVICE))
return NULL;
return ring;
}
/// Create a packet socket. If param ring is not NULL, the buffer is mapped
// #param ring will, if set, point to the mapped ring on return
// #return the socket fd
static int
init_packetsock(char **ring, int ringtype)
{
int fd;
// open packet socket
//fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
//fd = socket(AF_INET,SOCK_RAW,htons(ETH_P_ALL)); //ETH_P_ALL = 3
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd < 0) {
perror("open socket");
RETURN_ERROR(-1, "Root priliveges are required\nsocket() rx. \n");
}
if (ring) {
*ring = init_packetsock_ring(fd, ringtype);
if (!*ring) {
close(fd);
return -1;
}
}
return fd;
}
static int
exit_packetsock(int fd, char *ring)
{
if (munmap(ring, CONF_RING_FRAMES * getpagesize())) {
perror("munmap");
return 1;
}
if (close(fd)) {
perror("close");
return 1;
}
return 0;
}
/// transmit a packet using packet ring
// NOTE: for high rate processing try to batch system calls,
// by writing multiple packets to the ring before calling send()
//
// #param pkt is a packet from the network layer up (e.g., IP)
// #return 0 on success, -1 on failure
static int process_tx(int fd, char *ring, const char *pkt, int pktlen)
{
static int ring_offset = 0;
struct tpacket_hdr *header;
struct pollfd pollset;
char *off;
int ret;
// fetch a frame
// like in the PACKET_RX_RING case, we define frames to be a page long,
// including their header. This explains the use of getpagesize().
header = (void *) ring + (ring_offset * getpagesize());
assert((((unsigned long) header) & (getpagesize() - 1)) == 0);
while (header->tp_status != TP_STATUS_AVAILABLE) {
// if none available: wait on more data
pollset.fd = fd;
pollset.events = POLLOUT;
pollset.revents = 0;
ret = poll(&pollset, 1, 1000 /* don't hang */);
if (ret < 0) {
if (errno != EINTR) {
perror("poll");
return -1;
}
//return 0;
}
}
// fill data
off = ((void *) header) + (TPACKET_HDRLEN - sizeof(struct sockaddr_ll));
memcpy(off, pkt, pktlen);
// fill header
header->tp_len = pktlen;
header->tp_status = TP_STATUS_SEND_REQUEST;
// increase consumer ring pointer
ring_offset = (ring_offset + 1) & (CONF_RING_FRAMES - 1);
// notify kernel
return 0;
}
/// Example application that opens a packet socket with rx_ring
int main(int argc, char **argv)
{
char *ring;
char pkt[125] = {0x00,0x0c,0x29,0xa4,0xff,0xbc,0x40,0x25,0xc2,0xd9,0xfb,0x8c,0x08,0x00,0x45,0x00,0x00,0x6f,0x24,0x1b,0x40,0x00,0x40,0x06,0x02,0x4b,0x0a,0x00,0x00,0x07,0x0a,0x00,0x00,0x1d,0xb8,0x64,0x01,0xbb,0x80,0x9e,0xaa,0x77,0x17,0x6d,0xa2,0x04,0x80,0x18,0x00,0x73,0x03,0xa0,0x00,0x00,0x01,0x01,0x08,0x0a,0x01,0x27,0x8e,0xaf,0x00,0x01,0xe8,0x71,0x16,0x03,0x01,0x00,0x36,0x01,0x00,0x00,0x32,0x03,0x02,0x55,0xf5,0x01,0xa9,0xc0,0xca,0xae,0xd6,0xd2,0x9b,0x6a,0x79,0x6d,0x9a,0xe8,0x9d,0x78,0xe2,0x64,0x98,0xf0,0xac,0xcb,0x2c,0x0d,0x51,0xa5,0xf8,0xc4,0x0f,0x93,0x87,0x00,0x00,0x04,0x00,0x35,0x00,0xff,0x01,0x00,0x00,0x05,0x00,0x0f,0x00,0x01,0x01};
int fd;
printf("page size %x\n", getpagesize());
fd = init_packetsock(&ring, PACKET_TX_RING);
if (fd < 0)
return 1;
// TODO: make correct IP packet out of pkt
int i;
double startTs = getTS();
double currentTs;
int pktCnt = 0;
int sendCnt = 0;
while (1) {
for (i=0; i<1000; i++) {
pkt[1] ++; pktCnt++;
process_tx(fd, ring, pkt, 125);
}
if (sendto(fd, NULL, 0, 0, (void *) &txring_daddr, sizeof(txring_daddr)) < 0) {
perror("sendto");
return -1;
}
sendCnt++;
usleep(300);
currentTs = getTS();
if ((currentTs - startTs) >= 1.0) {
startTs += 1.0;
printf("%7d %6d\n", pktCnt, sendCnt);
pktCnt = 0; sendCnt = 0;
}
}
if (exit_packetsock(fd, ring))
return 1;
printf("OK\n");
return 0;
}
UPDATE1
The current NIC is RealTek RTL8111/8168/8411 NIC. After upgrading the driver to the version as of 8.044, the rate goes up to 135K/second.
Ran the same program on Intel 82577LM Gigabit NIC, got about 430K/seconds rate.
I need a shared memory which should have 2 fields
mh_data header;
and
a variable data field of any type of any lenght
I used the code->
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
//#include <conio.h>
#define ERROR -1
#define SUCCESS 0
typedef char int8;
typedef unsigned int u_int32;
typedef unsigned short u_int16;
typedef int error_code;
typedef union {
u_int32 group_user; /* group/user numbers */
struct {
u_int16 grp; /* group number */
u_int16 usr; /* user number */
} grp_usr;
} owner_id;
typedef struct mh_com {
u_int16
m_sync, /* sync bytes */
m_sysrev; /* system revision check value */
u_int32
m_size; /* module size */
owner_id
m_owner; /* group/user id */
u_int32
m_name; /* offset to module name */
u_int16
m_access, /* access permissions */
m_tylan, /* type/lang */
m_attrev, /* attributes/revision */
m_edit; /* edition */
u_int32
m_needs, /* module hardware requirements flags (reserved) */
m_share, /* shared data offset */
m_symbol, /* symbol table offset */
m_exec, /* offset to execution entry point */
m_excpt, /* offset to exception entry point */
m_data, /* data storage requirement */
m_stack, /* stack size */
m_idata, /* offset to initialized data */
m_idref, /* offset to data reference lists */
m_init, /* initialization routine offset */
m_term; /* termination routine offset */
u_int32
m_dbias, /* data area bias */
m_cbias; /* code area bias */
u_int16
m_ident; /* ident code for ident program */
char
m_spare[8]; /* reserved bytes */
u_int16
m_parity; /* header parity */
int8 m_shm_obj[256];
} mh_com, *Mh_com;
typedef mh_com mh_data;
error_code _os_datmod(
const char *mod_name,
u_int32 sz,
u_int16 *attr_rev,
u_int16 *type_lang,
u_int32 perm,
void **mod_data,
mh_data **mod_head)
{
struct datmod
{
mh_data header;
int size;
/*union Data
{
char str[sz];
}data;*/
char data[sz];
//void* dataPtr;
};
int fd;
int len;
struct stat shm_mod_stat;
void *addr;
len = strlen(mod_name);
/* Open new POSIX shared memory object */
if ((fd = shm_open(mod_name, O_RDWR |O_CREAT, /* mode_t */ 0666)) == -1)
{
/* TODO: If mod_name path is invalid, then return EOS_PNNF */
return ERROR;
}
if(ftruncate(fd, sizeof(struct datmod))==-1)
{
perror("ftruncate");
shm_unlink(mod_name);
return ERROR;
}
/* do mmap */
addr = (struct datmod *)mmap(NULL, sizeof(struct datmod), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
{
shm_unlink(mod_name);
return ERROR;
}
((struct datmod *)addr)->size = sz;
/* mmaped address */
*mod_data = &(((struct datmod *)addr)->data);
*mod_head = &(((struct datmod *)addr)->header);
//memset((((union Data*)(*mod_data))->str),0,sz);
memset(((*(char **)mod_data)),0,sz);
//(*mod_head)->m_shm_obj = (int8 *) malloc(len + 1);
memcpy(&((*mod_head)->m_shm_obj), (mod_name), len);
(*mod_head)->m_shm_obj[len] = '\0';
close(fd);
return SUCCESS;
}
int main()
{
void* data;
mh_data * header;
char str[] = "/Sandeep";
_os_datmod(str,50,0,0,0,&data, &header);
struct DATA
{
int i;
float j;
}*dat;
dat = (struct DATA *)(data);
dat->i = 5;
dat->j = 4.2;
//strcpy((char*)data , str);
int res = fork();
if(res==0)
{
_os_datmod(str,50,0,0,0,&data, &header);
dat = (struct DATA *)(data);
printf("i=%d,j=%f\n",dat->i,dat->j);
//printf("%s",(char *)data);
}
printf("hello world\n");
}
but it prints
hello world
i=0,j=0.000000
hello world
I also need to change
struct datmod
{
mh_data header;
int size;
/*union Data
{
char str[sz];
}data;*/
char data[sz];
//void* dataPtr;
};
so that
the data field can extend to any length and any type.
So, please suggest
I am currently working on a project involving a Cyclone V ARM Cortex A9 Processor and an external device. I am relatively new in C Programming. I am using the UART interface of the processor to send and receive data from the external with help of APIs in C. When i compile my code, I get warnings that I am passing arguments that make pointer from integer without a cast in the function alt_16550_fifo_write(). Can someone please help?
Below is my code
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h> // string function definitions
#include <unistd.h> // UNIX standard function definitions
#include <fcntl.h> // File control definitions
#include <errno.h> // Error number definitions
#include <termios.h> // POSIX terminal control definitions
#include <stdbool.h>
#include <sys/types.h>
#include "ergo.h"
#include "alt_clock_manager.h"
#include "hwlib.h"
#include "alt_clock_group.h"
#include "alt_hwlibs_ver.h"
#include "alt_16550_uart.h"
#include "uart.h"
#include "socal/alt_clkmgr.h"
#include "socal/alt_rstmgr.h"
#include "socal/alt_uart.h"
#include "socal/hps.h"
#include "socal/socal.h"
/* commands to control the ergo bike */
#define ERGO_CMD_GET_ADDRESS 0x11
#define ERGO_CMD_RUN_DATA 0x40
#define ERGO_CMD_SET_WATT 0x51
#define UART_MAX_DATA 20
#define enable_init TRUE
/*Global Variables*/
ergo_run_data_t ergo_run_data;
u_int8_t ergo_adr_int;
/* External Functions that are called in the main function*/
static ALT_STATUS_CODE alt_16550_reset_helper(ALT_16550_HANDLE_t * handle, bool enable_init);
static inline uint32_t alt_read_word_helper(const void * addr);
static ALT_STATUS_CODE alt_16550_write_divisor_helper(ALT_16550_HANDLE_t * handle,uint32_t divisor);
ALT_STATUS_CODE alt_clk_clock_enable(ALT_CLK_t ALT_CLK_L4_SP);
ALT_STATUS_CODE alt_clk_is_enabled(ALT_CLK_t ALT_CLK_L4_SP);
ALT_STATUS_CODE alt_clk_freq_get(ALT_CLK_t ALT_CLK_L4_SP,alt_freq_t* freq);
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
void ergo_get_address(ALT_16550_HANDLE_t * handle);
void ergo_get_run_data(void);
void ergo_set_watt(u_int8_t ergo_adr_int, u_int8_t watt);
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int);
void ergo_break(void);
/*function to enable the SOCFPGA UART Clock*/
ALT_STATUS_CODE alt_clk_clock_enable(ALT_CLK_t ALT_CLK_L4_SP)
{
if (alt_clk_clock_enable(ALT_CLK_L4_SP) != ALT_E_ERROR)
{
return ALT_E_SUCCESS; // The operation was successfull
}
else
{
return ALT_E_ERROR; // The operation was not successfull
}
}
/*Function to check whether the SOCFPGA Clock is enabled*/
ALT_STATUS_CODE alt_clk_is_enabled(ALT_CLK_t ALT_CLK_L4_SP)
{
ALT_16550_HANDLE_t * handle;
handle->clock_freq = 0;
if (alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE)
{
return ALT_E_BAD_CLK;
}
else
{
ALT_STATUS_CODE status;
status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
}
}
//function to get the clock frequency
ALT_STATUS_CODE alt_clk_freq_get(ALT_CLK_t ALT_CLK_L4_SP,alt_freq_t* freq)
{
ALT_16550_HANDLE_t * handle;
handle->clock_freq = 0;
ALT_STATUS_CODE status;
status = alt_clk_freq_get(ALT_CLK_L4_SP, &handle->clock_freq);
if (status != ALT_E_SUCCESS)
{
return status;
}
}
struct uart_data_t
{
size_t tx_count; /*amount of data to send*/
char tx_buffer[UART_MAX_DATA]; /*data to send*/
size_t rx_count; /*amount of data to send*/
char rx_buffer[UART_MAX_DATA]; /*data received*/
}uart_data_t;
/*==========================UART functions======================*/
/*----------------------------- uart_init() -------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Initialisiert UART-Schnittstelle
*---------------------------------------------------------------------*/
int main()
{
/* Open File Descriptor */
int USB = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY|O_NONBLOCK);
//Error Handling
if ( USB < 0 )
{
printf("Error beim oeffnen");
}
// Configure Port
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
// Error Handling
if ( tcgetattr ( USB, &tty ) != 0 )
{
printf("error beim tcgetattr");
}
// Save old tty parameters
tty_old = tty;
ALT_16550_HANDLE_t * handle;
handle->data;
handle->fcr;
handle->clock_freq;
handle->location; //ALT_UART0_ADDR
handle->device;
//ALT_16550_DEVICE_SOCFPGA_UART0 = 0; //This option selects UART0 in the SoC FPGA
ALT_16550_DEVICE_t device;
ALT_STATUS_CODE status;
alt_freq_t clock_freq;
void *location;
const void * addr;
bool enable_init;
uint32_t baudrate = ALT_16550_BAUDRATE_9600;
uint32_t divisor; //((handle->clock_freq + (8 * baudrate)) / (16 * baudrate));
printf("Program start \n");
// Enable the UART Clock
alt_clk_clock_enable(ALT_CLK_L4_SP);
// Helper function to reset and Initialise the UART (UART 0)
alt_16550_reset_helper(handle, enable_init);
// Helper function to carryout the actual register read.
alt_read_word_helper(addr);
//Helper function to write the divisor in Hardware
alt_16550_write_divisor_helper(handle,divisor);
//Enable the UART (UART 0)
alt_16550_enable(handle);
//Enable the FIFO
alt_16550_fifo_enable(handle);
//Get the Ergometer address
ergo_get_address(handle);
return 0;
}
/*--------------------------- ergo_get_adr() ------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Holen der Ergometer-Adreesse (1 Byte)
*---------------------------------------------------------------------*/
void ergo_get_address(ALT_16550_HANDLE_t * handle)
{
struct uart_data_t data;
/* build up data frame for address request */
data.tx_count = 1; // amount of data to send
data.tx_buffer[0] = ERGO_CMD_GET_ADDRESS;
data.rx_count = 2; /*amount of data to receive*/
/* get address from ergo bike */
alt_16550_fifo_write(handle, *ERGO_CMD_GET_ADDRESS,1);
alt_16550_fifo_read(handle,data.rx_buffer,2);
/* save ergo address if the bike responded */
if(data.rx_buffer[0] == ERGO_CMD_GET_ADDRESS)
{
ergo_adr_int = data.rx_buffer[1];
printf("%d\n",data.rx_buffer[1]);
}
/* wait for 50ms */
ergo_break();
return;
}
/*---------------------------- ergo_reset() -------------------------*/
/**
* Übergabeparameter: u_int8_t ergo_adr_int
* Return: -
* Funktion: Setzt Ergometer zurück
*---------------------------------------------------------------------*/
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int)
{
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
ergo_break();
return;
}
/*---------------------------- ergo_break() -------------------------*/
/**
* Übergabeparameter: -
* Return: -
* Funktion: Wait for about 50 ms
*---------------------------------------------------------------------*/
void ergo_break(void)
{
u_int16_t d1;
u_int8_t d2;
//wait for ~50 ms
for(d1=0; d1 < 65535; d1++)
{
for(d2=0; d2 < 64; d2++)
{
}
}
return;
}
In your code, your function prototype is
ALT_STATUS_CODE alt_16550_fifo_write
(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
the second parameter being const char * buffer.
While calling this function, you're using
void ergo_reset(ALT_16550_HANDLE_t * handle,u_int8_t ergo_adr_int)
{
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
ergo_break();
return;
}
here, 0x12 and ergo_adr_int are not of type const char *.
0x12 is an integer constant (hexadecimal constant, to be precise) #.
ergo_adr_int is of u_int8_t type.
Hence the mismatch and the warning(s).
To Resolve
You need to pass a const char * variable as the second argument of the fuunction.
# :: As per C11 standard document, chapter 6.4.4.1, Integer constants,
hexadecimal-constant:
hexadecimal-prefix hexadecimal-digit
hexadecimal-constant hexadecimal-digit
Where
hexadecimal-prefix: one of
0x 0X
and
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
Here is the declaration of you alt_16550_fifo_write function
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,const char * buffer,size_t count);
The second parameter is of a pointer type but in your program you are always passing integer values:
alt_16550_fifo_write(handle,0x12,1);
alt_16550_fifo_write(handle,ergo_adr_int,1);
You need to pass a pointer to a char. For example:
alt_16550_fifo_write(handle, &(char) {0x12}, 1);
or
char x = 0x12;
alt_16550_fifo_write(handle, &x, 1);
Prototype for alt_16550_fifo_write() is:
ALT_STATUS_CODE alt_16550_fifo_write(ALT_16550_HANDLE_t * handle,
const char * buffer, size_t count);
You are using it at two places:
alt_16550_fifo_write(handle, *ERGO_CMD_GET_ADDRESS,1);
...
alt_16550_fifo_write(handle,0x12,1);
The second parameter is wrong. It should be const char * buffer, for example some string.