#include <rtapi.h>
#include <rtapi_app.h>
#include <hal.h>
#include "../hal_priv.h"
#include "scope_rt.h"
#include "rtapi_string.h"
MODULE_AUTHOR("John Kasunich");
MODULE_DESCRIPTION("Oscilloscope for EMC HAL");
MODULE_LICENSE("GPL");
long num_samples = 16000;
long shm_size;
RTAPI_MP_LONG(num_samples, "Number of samples in the shared memory block")
scope_rt_control_t *ctrl_rt;
scope_shm_control_t *ctrl_shm;
static int comp_id;
static int shm_id;
static scope_rt_control_t ctrl_struct;
static void init_rt_control_struct(void *shmem);
static void init_shm_control_struct(void);
static void sample(void *arg, long period);
static void capture_sample(void);
static int check_trigger(void);
int rtapi_app_main(void)
{
int retval;
void *shm_base;
long skip;
comp_id = hal_init("scope_rt");
if (comp_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR, "SCOPE: ERROR: hal_init() failed\n");
return -1;
}
skip = (sizeof(scope_shm_control_t) + 3) & ~3;
shm_size = skip + num_samples * sizeof(scope_data_t);
shm_id = rtapi_shmem_new(SCOPE_SHM_KEY, comp_id, shm_size);
if (shm_id < 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"SCOPE RT: ERROR: failed to get shared memory (key=0x%x, size=%lu)\n",
SCOPE_SHM_KEY,
shm_size
);
hal_exit(comp_id);
return -1;
}
retval = rtapi_shmem_getptr(shm_id, &shm_base);
if (retval < 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"SCOPE: ERROR: failed to map shared memory\n");
rtapi_shmem_delete(shm_id, comp_id);
hal_exit(comp_id);
return -1;
}
ctrl_rt = &ctrl_struct;
init_rt_control_struct(shm_base);
retval = hal_export_funct("scope.sample", sample, NULL, 0, 0, comp_id);
if (retval != 0) {
rtapi_print_msg(RTAPI_MSG_ERR,
"SCOPE_RT: ERROR: sample funct export failed\n");
hal_exit(comp_id);
return -1;
}
rtapi_print_msg(RTAPI_MSG_DBG, "SCOPE_RT: installed sample function\n");
hal_ready(comp_id);
return 0;
}
void rtapi_app_exit(void)
{
if (ctrl_shm->thread_name[0] != '\0') {
hal_del_funct_from_thread("scope.sample", ctrl_shm->thread_name);
}
rtapi_shmem_delete(shm_id, comp_id);
hal_exit(comp_id);
}
static void sample(void *arg, long period)
{
int n;
ctrl_shm->watchdog = 0;
if (ctrl_shm->state == RESET) {
ctrl_shm->curr = 0;
ctrl_shm->start = ctrl_shm->curr;
ctrl_shm->samples = 0;
ctrl_shm->force_trig = 0;
ctrl_shm->state = IDLE;
}
ctrl_rt->mult_cntr++;
if (ctrl_rt->mult_cntr < ctrl_shm->mult) {
return;
}
ctrl_rt->mult_cntr = 0;
switch (ctrl_shm->state) {
case IDLE:
break;
case INIT:
ctrl_shm->curr = 0;
ctrl_shm->start = ctrl_shm->curr;
ctrl_shm->samples = 0;
ctrl_shm->force_trig = 0;
ctrl_rt->auto_timer = 0;
for (n = 0; n < 16; n++) {
ctrl_rt->data_addr[n] = SHMPTR(ctrl_shm->data_offset[n]);
ctrl_rt->data_type[n] = ctrl_shm->data_type[n];
ctrl_rt->data_len[n] = ctrl_shm->data_len[n];
}
ctrl_shm->state = PRE_TRIG;
break;
case PRE_TRIG:
capture_sample();
ctrl_shm->samples++;
if (ctrl_shm->samples >= ctrl_shm->pre_trig) {
ctrl_shm->state = TRIG_WAIT;
check_trigger();
}
break;
case TRIG_WAIT:
capture_sample();
ctrl_shm->samples++;
if (check_trigger()) {
ctrl_shm->state = POST_TRIG;
} else {
ctrl_shm->samples--;
ctrl_shm->start += ctrl_shm->sample_len;
if ((ctrl_shm->start + ctrl_shm->sample_len) > ctrl_shm->buf_len) {
ctrl_shm->start = 0;
}
}
break;
case POST_TRIG:
capture_sample();
ctrl_shm->samples++;
if (ctrl_shm->samples >= ctrl_shm->rec_len) {
ctrl_shm->state = DONE;
}
break;
case DONE:
break;
default:
ctrl_shm->state = IDLE;
break;
}
}
static void capture_sample(void)
{
scope_data_t *dest;
int n;
dest = &(ctrl_rt->buffer[ctrl_shm->curr]);
for (n = 0; n < 16; n++) {
switch (ctrl_rt->data_len[n]) {
case 1:
dest->d_u8 = *((unsigned char *) (ctrl_rt->data_addr[n]));
dest++;
break;
case 4:
dest->d_u32 = *((unsigned long *) (ctrl_rt->data_addr[n]));
dest++;
break;
case 8:
{
ireal_t sample_a, sample_b;
do {
sample_a = *((volatile ireal_t *) (ctrl_rt->data_addr[n]));
sample_b = *((volatile ireal_t *) (ctrl_rt->data_addr[n]));
} while( sample_a != sample_b );
dest->d_ireal = sample_a;
dest++;
}
break;
default:
break;
}
}
ctrl_shm->curr += ctrl_shm->sample_len;
if ((ctrl_shm->curr + ctrl_shm->sample_len) > ctrl_shm->buf_len) {
ctrl_shm->curr = 0;
}
}
static int check_trigger(void)
{
static int compare_result = 0;
int prev_compare_result;
scope_data_t *value, *level;
if (ctrl_shm->force_trig != 0) {
return 1;
}
if (ctrl_shm->auto_trig != 0) {
if (++ctrl_rt->auto_timer >= ctrl_shm->rec_len) {
return 1;
}
} else {
ctrl_rt->auto_timer = 0;
}
if (ctrl_shm->trig_chan == 0) {
return 0;
}
value = ctrl_rt->data_addr[ctrl_shm->trig_chan - 1];
level = &(ctrl_shm->trig_level);
prev_compare_result = compare_result;
switch (ctrl_rt->data_type[ctrl_shm->trig_chan - 1]) {
case HAL_BIT:
compare_result = value->d_u8;
break;
case HAL_FLOAT:
{
ireal_t tmp1, tmp2;
tmp1 = value->d_ireal;
tmp2 = level->d_ireal;
if (tmp1 & 0x8000000000000000ull) {
if (tmp2 & 0x8000000000000000ull) {
tmp1 ^= 0x8000000000000000ull;
tmp2 ^= 0x8000000000000000ull;
compare_result = (tmp1 < tmp2);
} else {
compare_result = 0;
}
} else {
if (tmp2 & 0x8000000000000000ull) {
compare_result = 1;
} else {
compare_result = (tmp1 > tmp2);
}
}
}
break;
case HAL_S32:
compare_result = (value->d_s32 > level->d_s32);
break;
case HAL_U32:
compare_result = (value->d_u32 > level->d_u32);
break;
default:
compare_result = 0;
break;
}
if (ctrl_shm->trig_edge && compare_result && !prev_compare_result) {
return 1;
}
if (!ctrl_shm->trig_edge && !compare_result && prev_compare_result) {
return 1;
}
return 0;
}
static void init_rt_control_struct(void *shmem)
{
char *cp;
int n, skip;
cp = (char *) ctrl_rt;
for (n = 0; n < sizeof(scope_rt_control_t); n++) {
cp[n] = 0;
}
ctrl_shm = shmem;
skip = (sizeof(scope_shm_control_t) + 3) & ~3;
ctrl_rt->buffer = (scope_data_t *) (((char *) (shmem)) + skip);
init_shm_control_struct();
}
static void init_shm_control_struct(void)
{
char *cp;
int skip, n;
cp = (char *) ctrl_shm;
for (n = 0; n < sizeof(scope_shm_control_t); n++) {
cp[n] = 0;
}
ctrl_shm->shm_size = shm_size;
skip = (sizeof(scope_shm_control_t) + 3) & ~3;
ctrl_shm->buf_len = (shm_size - skip) / sizeof(scope_data_t);
ctrl_shm->mult = 1;
ctrl_shm->state = IDLE;
}