/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file station.c * \brief The station management functions * \ingroup host * * This file provide station management functions * * \todo */ #include #include #include #include #include #include #include #include "ecos/packages/hal/maximus/arch/current/include/hal_host_intr.h" #include "host/inc/sci.h" #include "host/inc/station.h" #ifndef UNIT_TEST #include "host/inc/syscall.h" #endif /* awfull, but needed */ static sci_ctx_t _my_sci; static netclock_ctx_t _my_netclock; static fcall_ctx_t _my_fcall; static probe_ctx_t _my_probe; static netclock_callback_t _ecos_tick_cb; /** * fill buffer with the in/out pipe name for sci msg communication * \param suffix pipe name suffix; normaly "in" or "out" * \param buffer string buffer to fill in * \param max_size max size of buffer to be filled * \return the length of pipe name, -1 if failed with errno * - EINVAL if suffix or buffer are NULL * - ENOSPC if buffer is too small for pipe name */ //static int _get_pipe_name(char *suffix, unsigned short id, char *buffer, int max_size) //{ // /* code here */ // return 0; //} /** * station context initialization, with pipe opening * \param station pointer to station context to initialize * \return 0 if ok, -1 if failed with errno= * - EINVAL if station is NULL * - all errno generated by open() call */ int station_init(station_ctx_t *station) { if(station == NULL) { errno = EINVAL; return -1; } memset(station, '\0', sizeof(station_ctx_t)); station->pipe_in_fd = -1; station->pipe_out_fd = -1; station->pipe_log_fd = -1; /* get station id */ station->id = getpid(); /* set variables */ station->log_level = STATION_LOG_WARNING; /* build pipe names */ sprintf(station->pipe_log_name, "%s/%s_log_%d", STATION_PIPE_PATH, STATION_PIPE_PREFIX, station->id); unlink(station->pipe_log_name); sprintf(station->pipe_in_name, "%s/%s_in_%d", STATION_PIPE_PATH, STATION_PIPE_PREFIX, station->id); unlink(station->pipe_in_name); sprintf(station->pipe_out_name, "%s/%s_out_%d", STATION_PIPE_PATH, STATION_PIPE_PREFIX, station->id); unlink(station->pipe_out_name); /* open log */ if(mknod(station->pipe_log_name, 0770 | S_IFIFO, 0) < 0) goto failed; if((station->pipe_log_fd = open(station->pipe_log_name, O_RDWR | O_NONBLOCK, S_IRWXU | S_IRWXG)) < 0) goto failed; /* open in pipe */ if(mknod(station->pipe_in_name, 0770 | S_IFIFO, 0) < 0) { station_log(station, STATION_LOG_WARNING, "%s: failed to create fifo '%s' (errno=%d)", __FUNCTION__, station->pipe_in_name, errno); goto failed; } if((station->pipe_in_fd = open(station->pipe_in_name, O_RDWR | O_NONBLOCK, S_IRWXU | S_IRWXG)) < 0) { station_log(station, STATION_LOG_WARNING, "%s: failed to open fifo '%s' (errno=%d)", __FUNCTION__, station->pipe_in_name, errno); goto failed; } /* open out pipe */ if(mknod(station->pipe_out_name, 0770 | S_IFIFO, 0) < 0) { station_log(station, STATION_LOG_WARNING, "%s: failed to create fifo '%s' (errno=%d)", __FUNCTION__, station->pipe_out_name, errno); goto failed; } if((station->pipe_out_fd = open(station->pipe_out_name, O_RDWR | O_NONBLOCK, S_IRWXU | S_IRWXG)) < 0) { station_log(station, STATION_LOG_WARNING, "%s: failed to open fifo '%s' (errno=%d)", __FUNCTION__, station->pipe_out_name, errno); goto failed; } /* init all contexts */ station->sci = &_my_sci; sci_init(station->sci, station); station->netclock = &_my_netclock; netclock_init(station->netclock, station->sci); station->fcall = &_my_fcall; fcall_init(station->fcall, station->sci); station->probe = &_my_probe; //probe_init(station->probe, station); station->ecos_tick_cb = &_ecos_tick_cb; station->status = STATION_STATUS_RUNNING; #ifndef UNIT_TEST /* first call for tick */ station_ecos_set_itimer(station, TICK_HZ / 100); #endif /* UNIT_TEST */ return 0; failed: if(station->pipe_out_fd >= 0) close(station->pipe_out_fd); if(station->pipe_in_fd >= 0) close(station->pipe_in_fd); if(station->pipe_log_fd >= 0) close(station->pipe_log_fd); unlink(station->pipe_out_name); unlink(station->pipe_in_name); unlink(station->pipe_log_name); station->pipe_out_fd = -1; station->pipe_in_fd = -1; station->pipe_log_fd = -1; station->status = STATION_STATUS_ERROR; return -1; } /** * station context to clean and reset, with pipe closing * \param station pointer to station context to stop */ void station_down(station_ctx_t *station) { if((station == NULL) || (station->status != STATION_STATUS_INIT)) return; if(station->pipe_out_fd >= 0) close(station->pipe_out_fd); if(station->pipe_in_fd >= 0) close(station->pipe_in_fd); if(station->pipe_log_fd >= 0) close(station->pipe_log_fd); unlink(station->pipe_out_name); unlink(station->pipe_in_name); unlink(station->pipe_log_name); station->pipe_out_fd = -1; station->pipe_in_fd = -1; station->pipe_log_fd = -1; return; } /** * station is into idle state; it sends a sci 'idle' message and waits for sci message reception * \param station the current station context * \return 0 when message has been received and process
* -1 if an error happened with errno=
*
  • EINVAL: station is invalid
    *
  • all error codes from recv() call
*/ int station_idle(station_ctx_t *station) { unsigned char buffer[64]; sci_msg_t msg; fd_set read_fds; struct timeval timeout; int sel; if((station == NULL) || (station->status == STATION_STATUS_INIT)) //|| !station_is_initialized(station)) { errno = EINVAL; return -1; } if(station->status == STATION_STATUS_RUNNING) { /* init msg */ sci_msg_init(&msg, buffer, 64); /* fill system header */ sci_msg_push(&msg, sizeof(station_msg_hdr_t)); msg.hdr.station = (station_msg_hdr_t *)msg.data_begin; msg.hdr.station->version = SYSTEM_VERSION; msg.hdr.station->type = SYSTEM_TYPE_IDLE; msg.hdr.station->flags = 0; /* fill sci header and send msg */ sci_fill_hdr(station->sci, &msg, SCI_MSG_TYPE_SYSTEM, 0); if(sci_send(station->sci, &msg) < 0) { station_log(station, STATION_LOG_WARNING, "%s failed to send system idle (errno=%d)", __FUNCTION__, errno); return -1; } station->status = STATION_STATUS_IDLE; } /* don't wait for next message with unit tests */ if(station->is_unit_test) return 0; /* vait for next message with 1 second timeout */ FD_ZERO(&read_fds); FD_SET(station->pipe_in_fd, &read_fds); timeout.tv_sec = 1; timeout.tv_usec = 0; sel = select(station->pipe_in_fd + 1, &read_fds, NULL, NULL, &timeout); if(sel < 0) { station_log(station, STATION_LOG_WARNING, "%s select failed (errno=%d)", __FUNCTION__, errno); return -1; } else if(sel > 0) { station->status = STATION_STATUS_RUNNING; return sci_recv(station->sci); } else /* timeout */ return 0; } /** * callback function to set the eCos timer interrupt register */ static void _ecos_set_itimer_cb(void *data) { uint32_t *isr; isr = (uint32_t *)data; *isr |= CYGNUM_HAL_INTERRUPT_RTC; return; } /** * schedule an eCos tick event (every 10ms) * \param station pointer to station context * \param tick tick for event scheduling * \return 0 if ok, -1 if failed with errno= * - EINVAL if station id NULL or if wanted tick is to old */ int station_ecos_set_itimer(station_ctx_t *station, tick_t tick) { if((station == NULL) || (station->status == STATION_STATUS_INIT)) { errno = EINVAL; return -1; } return netclock_schedule(station->netclock, station->ecos_tick_cb, NETWORK_CLOCK_TYPE_STATION, tick, _ecos_set_itimer_cb, (void *)&maximus_pending_isrs); } /** * set the station log level * \param station pointer to station context * \param level new log level * \return 0 if ok, -1 if failed with errno= * - EINVAL if station is NULL or level is out of range */ int station_log_set_level(station_ctx_t *station, station_log_level_t level) { if((station == NULL) || (station->status == STATION_STATUS_INIT) || (level <= STATION_LOG_NONE) || (level >= STATION_LOG_NB)) { errno = EINVAL; return -1; } station->log_level = level; return 0; } /** * send message to station log system * \param station pointer to station context * \param level level of log message * \param format string structure describing the data log format * \param ... suite of parameters to fit the format */ void station_log(station_ctx_t *station, station_log_level_t level, const char *format, ...) { va_list va_args; int hdr_len; static char buffer[STATION_MAX_LOG_SIZE]; if((station == NULL) || (station->status == STATION_STATUS_INIT) || (format == NULL)) return; if ((level <= STATION_LOG_NONE) || (level > station->log_level)) return; if (station->pipe_log_fd < 0) return; /* build header and send it */ sprintf(buffer, "sta(%d) %Lu: %s", station->id, station->current_tick_tck, (level >= STATION_LOG_DEBUG ? "DEBUG ": "") ); hdr_len = strlen(buffer); write(station->pipe_log_fd, buffer, hdr_len); /* build body and send it */ buffer[STATION_MAX_LOG_SIZE - 1] = '\0'; va_start(va_args, format); vsnprintf(buffer, STATION_MAX_LOG_SIZE - 1, format, va_args); va_end (va_args); write(station->pipe_log_fd, buffer, strlen(buffer)); /* send CR */ write(station->pipe_log_fd, "\n", 1); return; }