From: krecmich Date: Mon, 10 Jun 2013 10:21:12 +0000 (+0200) Subject: First version of s-functions needed for opertaing mf624. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/mf624-simulink.git/commitdiff_plain/ac50e6ad8f2b22280368106e148b4e32214ea04d First version of s-functions needed for opertaing mf624. Signed-off-by: krecmich --- ac50e6ad8f2b22280368106e148b4e32214ea04d diff --git a/mf624.c b/mf624.c new file mode 100644 index 0000000..2575756 --- /dev/null +++ b/mf624.c @@ -0,0 +1,530 @@ +/* + * Application using MF624 UIO driver + * + * Copyright (C) 2011 Rostislav Lisovy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // uintX_t +#include +#include +#include + +#include "mf624.h" + +/****************************************************************/ + + +int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr) +{ + FILE *file; + void *s; + int ssiz; + static size_t page_size; + + page_size = sysconf(_SC_PAGESIZE); + + ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr); + if (ssiz < 0) + return -1; + /* add reserve to store each size addr, name, offset, size */ + ssiz += 6 + 1; + s = alloca(ssiz); + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) + return -1; + fscanf(file, "%"SCNiPTR, &barmap->phys_addr); + fclose(file); + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) { + barmap->offset = barmap->phys_addr & (page_size - 1); + } else { + fscanf(file, "%"SCNi32, &barmap->offset); + fclose(file); + } + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) + return -1; + fscanf(file, "%"SCNi32, &barmap->size); + fclose(file); + + barmap->mmap_offset = page_size * map_nr + barmap->offset; + + return 0; +} + +int bar_mapping_setup(bar_mapping_t *barmap, int device_fd) +{ + static size_t page_mask = 0; + off_t mmap_start; + size_t mmap_size; + + if (!page_mask) + page_mask = sysconf(_SC_PAGESIZE) - 1; + + mmap_start = barmap->mmap_offset & ~page_mask; + mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start; + mmap_size &= ~page_mask; + + barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start); + if (barmap->mmap_addr == MAP_FAILED) { + return -1; + } + + barmap->virt_addr = (uintptr_t)barmap->mmap_addr; + barmap->virt_addr += barmap->mmap_offset & page_mask; + + return 0; +} + +/****************************************************************/ + +#define BUFF_SMALL 32 +#define BUFF_MID 256 +#define min(a, b) ((a) > (b) ? (b) : (a)) + +/* Hardware specific */ +/* BAR0 */ +#define GPIOC_reg 0x54 + +/* BAR2 */ +#define ADCTRL_reg 0x00 +#define ADDATA0_reg 0x00 +#define ADDATA1_reg 0x02 +#define ADDATA2_reg 0x04 +#define ADDATA3_reg 0x06 +#define ADDATA4_reg 0x08 +#define ADDATA5_reg 0x0a +#define ADDATA6_reg 0x0c +#define ADDATA7_reg 0x0e +#define ADSTART_reg 0x20 + +#define DOUT_reg 0x10 +#define DIN_reg 0x10 +#define DA0_reg 0x20 +#define DA1_reg 0x22 +#define DA2_reg 0x24 +#define DA3_reg 0x26 +#define DA4_reg 0x28 +#define DA5_reg 0x2A +#define DA6_reg 0x2C +#define DA7_reg 0x2E + +#define GPIOC_DACEN_mask (1 << 26) +#define GPIOC_LDAC_mask (1 << 23) +#define GPIOC_EOLC_mask (1 << 17) + + + + +static uint32_t dac_channel2reg[] = { + [DA0] = DA0_reg, + [DA1] = DA1_reg, + [DA2] = DA2_reg, + [DA3] = DA3_reg, + [DA4] = DA4_reg, + [DA5] = DA5_reg, + [DA6] = DA6_reg, + [DA7] = DA7_reg, +}; + +static uint32_t adc_channel2reg[] = { + [AD0] = ADDATA0_reg, + [AD1] = ADDATA1_reg, + [AD2] = ADDATA2_reg, + [AD3] = ADDATA3_reg, + [AD4] = ADDATA4_reg, + [AD5] = ADDATA5_reg, + [AD6] = ADDATA6_reg, + [AD7] = ADDATA7_reg, +}; + + + +#define MFST2REG(mfst, bar_num, reg_offs) \ + ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs))) + +mf624_state_t mf624_state; + +/* Print one byte as binary number */ +void print_8bin(int nr) +{ + int i; + for (i = 7; i >= 0; i--) { + printf("%d" , ((nr & (1 << i)) > 0)); + } + + printf("\n"); +} + + + +void DIO_write(mf624_state_t* mfst, int16_t val) +{ + mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg)); +} + +uint16_t DIO_read(mf624_state_t* mfst) +{ + return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF; +} + +void DAC_enable(mf624_state_t* mfst) +{ + // Setting DACEN and LDAC bits in GPIO register influences all DACs + mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) + | GPIOC_DACEN_mask) // enable output + & ~GPIOC_LDAC_mask, // enable conversion + MFST2REG(mfst, 0, GPIOC_reg)); +} + + + +int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val) +{ + if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg)) + return -1; + + mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel])); + return 0; +} + +int ADC_enable(mf624_state_t* mfst, adc_channel_t channel) +{ + mfst->ADC_enabled = 0; + + if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg)) + return -1; + + mfst->ADC_enabled = (1 << channel); + + mfst->ADC_enabled &= 0xFF; + mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg)); + //print_8bin(ADC_enabled); + + return 0; +} + +/* This function blocks until conversion is finished */ +double ADC_read(mf624_state_t* mfst, adc_channel_t channel) +{ + volatile int i; + int result; + + // Activate trigger to start conversion + mf624_read16(MFST2REG(mfst, 2, ADSTART_reg)); + + // Check if conversion has finished + while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { + for (i = 0; i < 1000; i++) {} // small wait + } + + ADC_enable(mfst, channel); + result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg)); + + return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000; +} + + +int open_device(char* path) { + int device_fd; + + device_fd = open(path, O_RDWR | O_SYNC); + if (device_fd == -1) { + perror("open()"); + return -1; + } + + return device_fd; +} + +void wait_for_interrupts(int device_fd) +{ + read(device_fd, NULL, 1); +} + +int disable_interrupts(int device_fd) +{ + uint32_t control_value = 0; + int status; + + status = write(device_fd, &control_value, sizeof(uint32_t)); + if (status == -1) { + perror("write()"); + return -1; + } + + return status; +} + +int enable_interrupts(int device_fd) +{ + uint32_t control_value = 1; + int status; + + status = write(device_fd, &control_value, sizeof(uint32_t)); + if (status == -1) { + perror("write()"); + return -1; + } + + return status; +} + +void list_available_mem_regions(char* device) +{ + int status; + char path[] = "/sys/class/uio/"; + char subdir[] = "/maps/"; + char directory[BUFF_MID]; + memset(directory, '\0', BUFF_MID); + + DIR *dip; + struct dirent *dit; + + strncat(directory, path, strlen(path)); + strncat(directory, device, min(strlen(device), 8)); + strncat(directory, subdir, strlen(subdir)); + + dip = opendir(directory); + if (dip == NULL) { + perror("opendir"); + return; + } + + while ((dit = readdir(dip)) != NULL) { + if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) { + printf(" %s\n", dit->d_name); + } + } + + status = closedir(dip); + if (status == -1) { + perror("closedir()"); + return; + } + +} + + +void list_available_io_ports(char *device) +{ + int status; + char path[] = "/sys/class/uio/"; + char subdir[] = "/portio/"; + char directory[BUFF_MID]; + memset(directory, '\0', BUFF_MID); + + DIR *dip; + struct dirent *dit; + + strncat(directory, path, strlen(path)); + strncat(directory, device, min(strlen(device), 8)); + strncat(directory, subdir, strlen(subdir)); + + status = access(directory, F_OK); + if (status == -1) { + printf(" There are no IO port available\n"); + return; + } + + dip = opendir(directory); + if (dip == NULL) { + perror("opendir"); + return; + } + + while ((dit = readdir(dip)) != NULL) { + if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) { + printf(" %s\n", dit->d_name); + } + } + + status = closedir(dip); + if (status == -1) { + perror("closedir()"); + return; + } + +} + + +void run_simple_tests(char* dev_name) +{ + int status; + int device_fd; + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + + strncat(buff, "/dev/", 5); + strncat(buff, dev_name, min(strlen(dev_name), 8)); + + printf("Opening %s\n", buff); + + device_fd = open_device(buff); + if (device_fd != -1) { + printf("Tring to enable interrupts\n"); + status = enable_interrupts(device_fd); + if (status != -1) { + printf(" Probably OK\n"); + } + + printf("Tring to disable interrupts\n"); + status = disable_interrupts(device_fd); + if (status != -1) { + printf(" Probably OK\n"); + } + } + + + printf("Checking for available memory regions exported by the UIO driver\n"); + list_available_mem_regions(dev_name); + + printf("Checking for available IO ports exported by the UIO driver\n"); + list_available_io_ports(dev_name); +} + +int mmap_regions(mf624_state_t* mfst) +{ + if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) { + fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) { + fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) { + fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev); + return -1; + } + +#if 1 + printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr); + printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr); + printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr); + + printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr); + printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr); + printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr); +#endif + + return 0; +} + + +/*int main(int argc, char* argv[]) +{ + mf624_state_t* mfst = &mf624_state; + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + + if (argc < 2) { + printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]); + return 1; + } + + mfst->uio_dev = argv[1]; + + strncat(buff, "/dev/", 5); + strncat(buff, mfst->uio_dev, sizeof(buff) - 6); + + mfst->device_fd = open_device(buff); + if (mfst->device_fd < 0) { + fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno)); + return 2; + } + if (mmap_regions(mfst) < 0) { + fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno)); + return 2; + } + + DAC_enable(mfst); + + while (1){ + printf("Reading DIO: "); + print_8bin(DIO_read(mfst)); + sleep(1); + + printf("Setting DA1 to 10 V\n"); + DAC_write(mfst, DA1, 0x3FFF); + sleep(1); + + printf("Reading ADC0: "); + printf("%f V\n", ADC_read(mfst, AD0)); + sleep(1); + + printf("Reading ADC1: "); + printf("%f V\n", ADC_read(mfst, AD1)); + sleep(1); + + printf("Setting DIO to 0xff\n"); + DIO_write(mfst, 0xff); + sleep(1); + + printf("Setting DIO to 0x00\n"); + DIO_write(mfst, 0x00); + sleep(1); + + printf("Setting DA1 to 5 V\n"); + DAC_write(mfst, DA1, 0x3000); + sleep(1); + + printf("Reading ADC0: "); + printf("%f V\n", ADC_read(mfst, AD0)); + sleep(1); + + printf("Reading ADC1: "); + printf("%f V\n", ADC_read(mfst, AD1)); + sleep(1); + printf("----------------------\n\n"); + } + + + return 0; +}*/ diff --git a/mf624.c~ b/mf624.c~ new file mode 100644 index 0000000..6ce3d5b --- /dev/null +++ b/mf624.c~ @@ -0,0 +1,530 @@ +/* + * Application using MF624 UIO driver + * + * Copyright (C) 2011 Rostislav Lisovy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // uintX_t +#include +#include +#include + +#include "mf624.h" + +/****************************************************************/ + + +int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr) +{ + FILE *file; + void *s; + int ssiz; + static size_t page_size; + + page_size = sysconf(_SC_PAGESIZE); + + ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr); + if (ssiz < 0) + return -1; + /* add reserve to store each size addr, name, offset, size */ + ssiz += 6 + 1; + s = alloca(ssiz + 6 + 1); + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) + return -1; + fscanf(file, "%"SCNiPTR, &barmap->phys_addr); + fclose(file); + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) { + barmap->offset = barmap->phys_addr & (page_size - 1); + } else { + fscanf(file, "%"SCNi32, &barmap->offset); + fclose(file); + } + + snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr); + file = fopen(s, "rb"); + if (file == NULL) + return -1; + fscanf(file, "%"SCNi32, &barmap->size); + fclose(file); + + barmap->mmap_offset = page_size * map_nr + barmap->offset; + + return 0; +} + +int bar_mapping_setup(bar_mapping_t *barmap, int device_fd) +{ + static size_t page_mask = 0; + off_t mmap_start; + size_t mmap_size; + + if (!page_mask) + page_mask = sysconf(_SC_PAGESIZE) - 1; + + mmap_start = barmap->mmap_offset & ~page_mask; + mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start; + mmap_size &= ~page_mask; + + barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start); + if (barmap->mmap_addr == MAP_FAILED) { + return -1; + } + + barmap->virt_addr = (uintptr_t)barmap->mmap_addr; + barmap->virt_addr += barmap->mmap_offset & page_mask; + + return 0; +} + +/****************************************************************/ + +#define BUFF_SMALL 32 +#define BUFF_MID 256 +#define min(a, b) ((a) > (b) ? (b) : (a)) + +/* Hardware specific */ +/* BAR0 */ +#define GPIOC_reg 0x54 + +/* BAR2 */ +#define ADCTRL_reg 0x00 +#define ADDATA0_reg 0x00 +#define ADDATA1_reg 0x02 +#define ADDATA2_reg 0x04 +#define ADDATA3_reg 0x06 +#define ADDATA4_reg 0x08 +#define ADDATA5_reg 0x0a +#define ADDATA6_reg 0x0c +#define ADDATA7_reg 0x0e +#define ADSTART_reg 0x20 + +#define DOUT_reg 0x10 +#define DIN_reg 0x10 +#define DA0_reg 0x20 +#define DA1_reg 0x22 +#define DA2_reg 0x24 +#define DA3_reg 0x26 +#define DA4_reg 0x28 +#define DA5_reg 0x2A +#define DA6_reg 0x2C +#define DA7_reg 0x2E + +#define GPIOC_DACEN_mask (1 << 26) +#define GPIOC_LDAC_mask (1 << 23) +#define GPIOC_EOLC_mask (1 << 17) + + + + +static uint32_t dac_channel2reg[] = { + [DA0] = DA0_reg, + [DA1] = DA1_reg, + [DA2] = DA2_reg, + [DA3] = DA3_reg, + [DA4] = DA4_reg, + [DA5] = DA5_reg, + [DA6] = DA6_reg, + [DA7] = DA7_reg, +}; + +static uint32_t adc_channel2reg[] = { + [AD0] = ADDATA0_reg, + [AD1] = ADDATA1_reg, + [AD2] = ADDATA2_reg, + [AD3] = ADDATA3_reg, + [AD4] = ADDATA4_reg, + [AD5] = ADDATA5_reg, + [AD6] = ADDATA6_reg, + [AD7] = ADDATA7_reg, +}; + + + +#define MFST2REG(mfst, bar_num, reg_offs) \ + ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs))) + +mf624_state_t mf624_state; + +/* Print one byte as binary number */ +void print_8bin(int nr) +{ + int i; + for (i = 7; i >= 0; i--) { + printf("%d" , ((nr & (1 << i)) > 0)); + } + + printf("\n"); +} + + + +void DIO_write(mf624_state_t* mfst, int16_t val) +{ + mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg)); +} + +uint16_t DIO_read(mf624_state_t* mfst) +{ + return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF; +} + +void DAC_enable(mf624_state_t* mfst) +{ + // Setting DACEN and LDAC bits in GPIO register influences all DACs + mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) + | GPIOC_DACEN_mask) // enable output + & ~GPIOC_LDAC_mask, // enable conversion + MFST2REG(mfst, 0, GPIOC_reg)); +} + + + +int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val) +{ + if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg)) + return -1; + + mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel])); + return 0; +} + +int ADC_enable(mf624_state_t* mfst, adc_channel_t channel) +{ + mfst->ADC_enabled = 0; + + if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg)) + return -1; + + mfst->ADC_enabled = (1 << channel); + + mfst->ADC_enabled &= 0xFF; + mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg)); + //print_8bin(ADC_enabled); + + return 0; +} + +/* This function blocks until conversion is finished */ +double ADC_read(mf624_state_t* mfst, adc_channel_t channel) +{ + volatile int i; + int result; + + // Activate trigger to start conversion + mf624_read16(MFST2REG(mfst, 2, ADSTART_reg)); + + // Check if conversion has finished + while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { + for (i = 0; i < 1000; i++) {} // small wait + } + + ADC_enable(mfst, channel); + result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg)); + + return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000; +} + + +int open_device(char* path) { + int device_fd; + + device_fd = open(path, O_RDWR | O_SYNC); + if (device_fd == -1) { + perror("open()"); + return -1; + } + + return device_fd; +} + +void wait_for_interrupts(int device_fd) +{ + read(device_fd, NULL, 1); +} + +int disable_interrupts(int device_fd) +{ + uint32_t control_value = 0; + int status; + + status = write(device_fd, &control_value, sizeof(uint32_t)); + if (status == -1) { + perror("write()"); + return -1; + } + + return status; +} + +int enable_interrupts(int device_fd) +{ + uint32_t control_value = 1; + int status; + + status = write(device_fd, &control_value, sizeof(uint32_t)); + if (status == -1) { + perror("write()"); + return -1; + } + + return status; +} + +void list_available_mem_regions(char* device) +{ + int status; + char path[] = "/sys/class/uio/"; + char subdir[] = "/maps/"; + char directory[BUFF_MID]; + memset(directory, '\0', BUFF_MID); + + DIR *dip; + struct dirent *dit; + + strncat(directory, path, strlen(path)); + strncat(directory, device, min(strlen(device), 8)); + strncat(directory, subdir, strlen(subdir)); + + dip = opendir(directory); + if (dip == NULL) { + perror("opendir"); + return; + } + + while ((dit = readdir(dip)) != NULL) { + if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) { + printf(" %s\n", dit->d_name); + } + } + + status = closedir(dip); + if (status == -1) { + perror("closedir()"); + return; + } + +} + + +void list_available_io_ports(char *device) +{ + int status; + char path[] = "/sys/class/uio/"; + char subdir[] = "/portio/"; + char directory[BUFF_MID]; + memset(directory, '\0', BUFF_MID); + + DIR *dip; + struct dirent *dit; + + strncat(directory, path, strlen(path)); + strncat(directory, device, min(strlen(device), 8)); + strncat(directory, subdir, strlen(subdir)); + + status = access(directory, F_OK); + if (status == -1) { + printf(" There are no IO port available\n"); + return; + } + + dip = opendir(directory); + if (dip == NULL) { + perror("opendir"); + return; + } + + while ((dit = readdir(dip)) != NULL) { + if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) { + printf(" %s\n", dit->d_name); + } + } + + status = closedir(dip); + if (status == -1) { + perror("closedir()"); + return; + } + +} + + +void run_simple_tests(char* dev_name) +{ + int status; + int device_fd; + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + + strncat(buff, "/dev/", 5); + strncat(buff, dev_name, min(strlen(dev_name), 8)); + + printf("Opening %s\n", buff); + + device_fd = open_device(buff); + if (device_fd != -1) { + printf("Tring to enable interrupts\n"); + status = enable_interrupts(device_fd); + if (status != -1) { + printf(" Probably OK\n"); + } + + printf("Tring to disable interrupts\n"); + status = disable_interrupts(device_fd); + if (status != -1) { + printf(" Probably OK\n"); + } + } + + + printf("Checking for available memory regions exported by the UIO driver\n"); + list_available_mem_regions(dev_name); + + printf("Checking for available IO ports exported by the UIO driver\n"); + list_available_io_ports(dev_name); +} + +int mmap_regions(mf624_state_t* mfst) +{ + if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) { + fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) { + fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) { + fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev); + return -1; + } + + if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) { + fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev); + return -1; + } + +#if 1 + printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr); + printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr); + printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr); + + printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr); + printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr); + printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr); +#endif + + return 0; +} + + +/*int main(int argc, char* argv[]) +{ + mf624_state_t* mfst = &mf624_state; + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + + if (argc < 2) { + printf("Usage: %s UIO_DEVICE\n UIO_DEVICE\tname of uio device in /dev\n", argv[0]); + return 1; + } + + mfst->uio_dev = argv[1]; + + strncat(buff, "/dev/", 5); + strncat(buff, mfst->uio_dev, sizeof(buff) - 6); + + mfst->device_fd = open_device(buff); + if (mfst->device_fd < 0) { + fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno)); + return 2; + } + if (mmap_regions(mfst) < 0) { + fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno)); + return 2; + } + + DAC_enable(mfst); + + while (1){ + printf("Reading DIO: "); + print_8bin(DIO_read(mfst)); + sleep(1); + + printf("Setting DA1 to 10 V\n"); + DAC_write(mfst, DA1, 0x3FFF); + sleep(1); + + printf("Reading ADC0: "); + printf("%f V\n", ADC_read(mfst, AD0)); + sleep(1); + + printf("Reading ADC1: "); + printf("%f V\n", ADC_read(mfst, AD1)); + sleep(1); + + printf("Setting DIO to 0xff\n"); + DIO_write(mfst, 0xff); + sleep(1); + + printf("Setting DIO to 0x00\n"); + DIO_write(mfst, 0x00); + sleep(1); + + printf("Setting DA1 to 5 V\n"); + DAC_write(mfst, DA1, 0x3000); + sleep(1); + + printf("Reading ADC0: "); + printf("%f V\n", ADC_read(mfst, AD0)); + sleep(1); + + printf("Reading ADC1: "); + printf("%f V\n", ADC_read(mfst, AD1)); + sleep(1); + printf("----------------------\n\n"); + } + + + return 0; +}*/ diff --git a/mf624.h b/mf624.h new file mode 100644 index 0000000..b574765 --- /dev/null +++ b/mf624.h @@ -0,0 +1,82 @@ +#ifndef MF624 +#define MF624 + +#include +#include // uintX_t +#include + + +typedef struct bar_mapping_t { + uintptr_t virt_addr; + void * mmap_addr; + off_t mmap_offset; + uintptr_t phys_addr; + uint32_t size; + uint32_t offset; +} bar_mapping_t; + + +typedef enum {DA0, DA1, DA2, DA3, DA4, DA5, DA6, DA7} dac_channel_t; +typedef enum {AD0, AD1, AD2, AD3, AD4, AD5, AD6, AD7} adc_channel_t; + +typedef struct mf624_state_t { + int device_fd; + char *uio_dev; + bar_mapping_t bar0; + bar_mapping_t bar2; + bar_mapping_t bar4; + int status; + int ADC_enabled; // Which ADCs are enabled +} mf624_state_t; + +extern mf624_state_t mf624_state; + +extern void print_8bin(int nr); + +static inline int16_t mf624_read16(void *ptr) +{ + return *(volatile uint16_t*)ptr; +} + +static inline int32_t mf624_read32(void *ptr) +{ + return *(volatile uint32_t*) ptr; +} + +static inline void mf624_write16(uint16_t val, void *ptr) +{ + *(volatile uint16_t*) ptr = val; +} + +static inline void mf624_write32(uint32_t val, void *ptr) +{ + *(volatile uint32_t*) ptr = val; +} + +extern void DIO_write(mf624_state_t* mfst, int16_t val); + +extern uint16_t DIO_read(mf624_state_t* mfst); + +extern void DAC_enable(mf624_state_t* mfst); + +extern int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val); + +extern int ADC_enable(mf624_state_t* mfst, adc_channel_t channel); + +extern double ADC_read(mf624_state_t* mfst, adc_channel_t channel); + +extern int open_device(char* path); + +extern void wait_for_interrupts(int device_fd); + +extern int disable_interrupts(int device_fd); + +extern int enable_interrupts(int device_fd); + +extern void list_available_mem_regions(char* device); + +extern void list_available_io_ports(char *device); + +extern int mmap_regions(mf624_state_t* mfst); + +#endif diff --git a/mf624.h~ b/mf624.h~ new file mode 100644 index 0000000..13a2739 --- /dev/null +++ b/mf624.h~ @@ -0,0 +1,80 @@ +#ifndef MF624 +#define MF624 + +#include +#include // uintX_t +#include + + +typedef struct bar_mapping_t { + uintptr_t virt_addr; + void * mmap_addr; + uintptr_t phys_addr; + uint32_t size; + uint32_t offset; +} bar_mapping_t; + +typedef enum {DA0, DA1, DA2, DA3, DA4, DA5, DA6, DA7} dac_channel_t; +typedef enum {AD0, AD1, AD2, AD3, AD4, AD5, AD6, AD7} adc_channel_t; + +typedef struct mf624_state_t { + int device_fd; + char *uio_dev; + bar_mapping_t bar0; + bar_mapping_t bar2; + bar_mapping_t bar4; + int status; + int ADC_enabled; // Which ADCs are enabled +} mf624_state_t; + +extern mf624_state_t mf624_state; + +extern void print_8bin(int nr); + +static inline int16_t mf624_read16(void *ptr) +{ + return *(volatile uint16_t*)ptr; +} + +static inline int32_t mf624_read32(void *ptr) +{ + return *(volatile uint32_t*) ptr; +} + +static inline void mf624_write16(uint16_t val, void *ptr) +{ + *(volatile uint16_t*) ptr = val; +} + +static inline void mf624_write32(uint32_t val, void *ptr) +{ + *(volatile uint32_t*) ptr = val; +} + +extern void DIO_write(mf624_state_t* mfst, int16_t val); + +extern uint16_t DIO_read(mf624_state_t* mfst); + +extern void DAC_enable(mf624_state_t* mfst); + +extern int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val); + +extern int ADC_enable(mf624_state_t* mfst, adc_channel_t channel); + +extern double ADC_read(mf624_state_t* mfst, adc_channel_t channel); + +extern int open_device(char* path); + +extern void wait_for_interrupts(int device_fd); + +extern int disable_interrupts(int device_fd); + +extern int enable_interrupts(int device_fd); + +extern void list_available_mem_regions(char* device); + +extern void list_available_io_ports(char *device); + +extern int mmap_regions(mf624_state_t* mfst); + +#endif diff --git a/mf624.mexa64 b/mf624.mexa64 new file mode 100755 index 0000000..c675168 Binary files /dev/null and b/mf624.mexa64 differ diff --git a/sfAnalogInput.c b/sfAnalogInput.c new file mode 100644 index 0000000..bfee43a --- /dev/null +++ b/sfAnalogInput.c @@ -0,0 +1,224 @@ +/* + * (c) Michal Kreč, Czech Technical University in Prague, 2013 + */ + + +/* + * You must specify the S_FUNCTION_NAME as the name of your S-function + * (i.e. replace sfuntmpl_basic with the name of your S-function). + */ + +#define S_FUNCTION_NAME sfAnalogInput +#define S_FUNCTION_LEVEL 2 + +/* + * Need to include simstruc.h for the definition of the SimStruct and + * its associated macro definitions. + */ +#include "simstruc.h" + +#include "mf624.h" + + +/* Error handling + * -------------- + * + * You should use the following technique to report errors encountered within + * an S-function: + * + * ssSetErrorStatus(S,"Error encountered due to ..."); + * return; + * + * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. + * It cannot be a local variable. For example the following will cause + * unpredictable errors: + * + * mdlOutputs() + * { + * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} + * sprintf(msg,"Error due to %s", string); + * ssSetErrorStatus(S,msg); + * return; + * } + * + * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. + */ + +/*====================* + * S-function methods * + *====================*/ + +/* Function: mdlInitializeSizes =============================================== + * Abstract: + * The sizes information is used by Simulink to determine the S-function + * block's characteristics (number of inputs, outputs, states, etc.). + */ +static void mdlInitializeSizes(SimStruct *S) +{ + /* See sfuntmpl_doc.c for more details on the macros below */ + + ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ + if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { + /* Return if number of expected != number of actual parameters */ + return; + } + + ssSetNumContStates(S, 0); + ssSetNumDiscStates(S, 0); + + if (!ssSetNumInputPorts(S, 1)) return; + ssSetInputPortWidth(S, 0, 1); + ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ + /* + * Set direct feedthrough flag (1=yes, 0=no). + * A port has direct feedthrough if the input is used in either + * the mdlOutputs or mdlGetTimeOfNextVarHit functions. + * See matlabroot/simulink/src/sfuntmpl_directfeed.txt. + */ + ssSetInputPortDirectFeedThrough(S, 0, 1); + + if (!ssSetNumOutputPorts(S, 1)) return; + ssSetOutputPortWidth(S, 0, 1); + + ssSetNumSampleTimes(S, 1); + ssSetNumRWork(S, 0); + ssSetNumIWork(S, 0); + ssSetNumPWork(S, 1); + ssSetNumModes(S, 0); + ssSetNumNonsampledZCs(S, 0); + + /* Specify the sim state compliance to be same as a built-in block */ + ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); + + ssSetOptions(S, 0); +} + + + +/* Function: mdlInitializeSampleTimes ========================================= + * Abstract: + * This function is used to specify the sample time(s) for your + * S-function. You must register the same number of sample times as + * specified in ssSetNumSampleTimes. + */ +static void mdlInitializeSampleTimes(SimStruct *S) +{ + ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); + ssSetOffsetTime(S, 0, 0.0); + +} + + + +#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ +#if defined(MDL_INITIALIZE_CONDITIONS) + /* Function: mdlInitializeConditions ======================================== + * Abstract: + * In this function, you should initialize the continuous and discrete + * states for your S-function block. The initial states are placed + * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). + * You can also perform any other initialization activities that your + * S-function may require. Note, this routine will be called at the + * start of simulation and if it is present in an enabled subsystem + * configured to reset states, it will be call when the enabled subsystem + * restarts execution to reset the states. + */ + static void mdlInitializeConditions(SimStruct *S) + { + } +#endif /* MDL_INITIALIZE_CONDITIONS */ + + + +#define MDL_START /* Change to #undef to remove function */ +#if defined(MDL_START) + /* Function: mdlStart ======================================================= + * Abstract: + * This function is called once at start of model execution. If you + * have states that should be initialized once, this is the place + * to do it. + */ + static void mdlStart(SimStruct *S) + { + #if defined(TEST) + mf624_state_t* mfst = &mf624_state; + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + + + + #endif + //TODO: inicializovat tady pointer na stavovou strukturu a ulozit ho do PWork + } +#endif /* MDL_START */ + + + +/* Function: mdlOutputs ======================================================= + * Abstract: + * In this function, you compute the outputs of your S-function + * block. + */ +static void mdlOutputs(SimStruct *S, int_T tid) +{ + mf624_state_t* mfstPtr = ssGetPWork(S)[0]; + real_T *y = ssGetOutputPortSignal(S,0); + y[0] = ADC_read(mfstPtr, AD0); +} + + + +#define MDL_UPDATE /* Change to #undef to remove function */ +#if defined(MDL_UPDATE) + /* Function: mdlUpdate ====================================================== + * Abstract: + * This function is called once for every major integration time step. + * Discrete states are typically updated here, but this function is useful + * for performing any tasks that should only take place once per + * integration step. + */ + static void mdlUpdate(SimStruct *S, int_T tid) + { + } +#endif /* MDL_UPDATE */ + + + +#define MDL_DERIVATIVES /* Change to #undef to remove function */ +#if defined(MDL_DERIVATIVES) + /* Function: mdlDerivatives ================================================= + * Abstract: + * In this function, you compute the S-function block's derivatives. + * The derivatives are placed in the derivative vector, ssGetdX(S). + */ + static void mdlDerivatives(SimStruct *S) + { + } +#endif /* MDL_DERIVATIVES */ + + + +/* Function: mdlTerminate ===================================================== + * Abstract: + * In this function, you should perform any actions that are necessary + * at the termination of a simulation. For example, if memory was + * allocated in mdlStart, this is the place to free it. + */ +static void mdlTerminate(SimStruct *S) +{ +} + + +/*======================================================* + * See sfuntmpl_doc.c for the optional S-function methods * + *======================================================*/ + +/*=============================* + * Required S-function trailer * + *=============================*/ + +#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ +#include "simulink.c" /* MEX-file interface mechanism */ +#else +#include "cg_sfun.h" /* Code generation registration function */ +#endif diff --git a/sfAnalogInput.mexa64 b/sfAnalogInput.mexa64 new file mode 100755 index 0000000..3cc9ff9 Binary files /dev/null and b/sfAnalogInput.mexa64 differ diff --git a/sfAnalogOutput.c b/sfAnalogOutput.c new file mode 100644 index 0000000..a3fa03d --- /dev/null +++ b/sfAnalogOutput.c @@ -0,0 +1,258 @@ +/* + * sfuntmpl_basic.c: Basic 'C' template for a level 2 S-function. + * + * ------------------------------------------------------------------------- + * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | + * ------------------------------------------------------------------------- + * + * Copyright 1990-2002 The MathWorks, Inc. + * $Revision: 1.27.4.2 $ + */ + + +/* + * You must specify the S_FUNCTION_NAME as the name of your S-function + * (i.e. replace sfuntmpl_basic with the name of your S-function). + */ + +#define S_FUNCTION_NAME sfAnalogOutput +#define S_FUNCTION_LEVEL 2 + +/* + * Need to include simstruc.h for the definition of the SimStruct and + * its associated macro definitions. + */ +#include "simstruc.h" +#include "mf624.h" + +/* Error handling + * -------------- + * + * You should use the following technique to report errors encountered within + * an S-function: + * + * ssSetErrorStatus(S,"Error encountered due to ..."); + * return; + * + * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. + * It cannot be a local variable. For example the following will cause + * unpredictable errors: + * + * mdlOutputs() + * { + * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} + * sprintf(msg,"Error due to %s", string); + * ssSetErrorStatus(S,msg); + * return; + * } + * + * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. + */ + +/*====================* + * S-function methods * + *====================*/ + +/* Function: mdlInitializeSizes =============================================== + * Abstract: + * The sizes information is used by Simulink to determine the S-function + * block's characteristics (number of inputs, outputs, states, etc.). + */ +static void mdlInitializeSizes(SimStruct *S) +{ + /* See sfuntmpl_doc.c for more details on the macros below */ + + ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ + if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { + /* Return if number of expected != number of actual parameters */ + return; + } + + ssSetNumContStates(S, 0); + ssSetNumDiscStates(S, 0); + + if (!ssSetNumInputPorts(S, 1)) return; + ssSetInputPortWidth(S, 0, 1); + ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ + /* + * Set direct feedthrough flag (1=yes, 0=no). + * A port has direct feedthrough if the input is used in either + * the mdlOutputs or mdlGetTimeOfNextVarHit functions. + * See matlabroot/simulink/src/sfuntmpl_directfeed.txt. + */ + ssSetInputPortDirectFeedThrough(S, 0, 1); + + if (!ssSetNumOutputPorts(S, 0)) return; + + ssSetNumSampleTimes(S, 1); + ssSetNumRWork(S, 0); + ssSetNumIWork(S, 0); + ssSetNumPWork(S, 1); + ssSetNumModes(S, 0); + ssSetNumNonsampledZCs(S, 0); + + /* Specify the sim state compliance to be same as a built-in block */ + ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); + + ssSetOptions(S, 0); +} + + + +/* Function: mdlInitializeSampleTimes ========================================= + * Abstract: + * This function is used to specify the sample time(s) for your + * S-function. You must register the same number of sample times as + * specified in ssSetNumSampleTimes. + */ +static void mdlInitializeSampleTimes(SimStruct *S) +{ + ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); + ssSetOffsetTime(S, 0, 0.0); + +} + + + +#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ +#if defined(MDL_INITIALIZE_CONDITIONS) + /* Function: mdlInitializeConditions ======================================== + * Abstract: + * In this function, you should initialize the continuous and discrete + * states for your S-function block. The initial states are placed + * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). + * You can also perform any other initialization activities that your + * S-function may require. Note, this routine will be called at the + * start of simulation and if it is present in an enabled subsystem + * configured to reset states, it will be call when the enabled subsystem + * restarts execution to reset the states. + */ + static void mdlInitializeConditions(SimStruct *S) + { + } +#endif /* MDL_INITIALIZE_CONDITIONS */ + + + +#define MDL_START /* Change to #undef to remove function */ +#if defined(MDL_START) + /* Function: mdlStart ======================================================= + * Abstract: + * This function is called once at start of model execution. If you + * have states that should be initialized once, this is the place + * to do it. + */ + static void mdlStart(SimStruct *S) + { + //TODO: get pointer to mfst state structure and store it in pwork + #define TEST + #if defined(TEST) + #define BUFF_SMALL 32 + mf624_state_t* mfst = malloc(sizeof(mf624_state_t)); + char buff[BUFF_SMALL]; + memset(buff, '\0', BUFF_SMALL); + mfst->uio_dev = "uio0"; + + strncat(buff, "/dev/", 5); + strncat(buff, mfst->uio_dev, sizeof(buff) - 6); + + mfst->device_fd = open_device(buff); + if (mfst->device_fd < 0) { + ssSetErrorStatus(S,"open failed"); + return; + } + if (mmap_regions(mfst) < 0) { + ssSetErrorStatus(S,"mmap_regions failed"); + return; + } + + DAC_enable(mfst); + ssSetPWorkValue(S, 0, mfst); + #endif + } +#endif /* MDL_START */ + + + +/* Function: mdlOutputs ======================================================= + * Abstract: + * In this function, you compute the outputs of your S-function + * block. + */ +static void mdlOutputs(SimStruct *S, int_T tid) +{ + const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); + mf624_state_t* mfst = ssGetPWorkValue(S,0); + int out; + if(u[0] > 9.9988){ + out = 0x3FFF; + } + else if(u[0] < -10){ + out = 0; + } + else { + out = (int) ((u[0] + 10) * 8192 / 10 + 0.5); + } + DAC_write(mfst, DA0, out); +} + + + +#define MDL_UPDATE /* Change to #undef to remove function */ +#if defined(MDL_UPDATE) + /* Function: mdlUpdate ====================================================== + * Abstract: + * This function is called once for every major integration time step. + * Discrete states are typically updated here, but this function is useful + * for performing any tasks that should only take place once per + * integration step. + */ + static void mdlUpdate(SimStruct *S, int_T tid) + { + } +#endif /* MDL_UPDATE */ + + + +#define MDL_DERIVATIVES /* Change to #undef to remove function */ +#if defined(MDL_DERIVATIVES) + /* Function: mdlDerivatives ================================================= + * Abstract: + * In this function, you compute the S-function block's derivatives. + * The derivatives are placed in the derivative vector, ssGetdX(S). + */ + static void mdlDerivatives(SimStruct *S) + { + } +#endif /* MDL_DERIVATIVES */ + + + +/* Function: mdlTerminate ===================================================== + * Abstract: + * In this function, you should perform any actions that are necessary + * at the termination of a simulation. For example, if memory was + * allocated in mdlStart, this is the place to free it. + */ +static void mdlTerminate(SimStruct *S) +{ + #if defined(TEST) + free(ssGetPWorkValue(S,0)); + #endif + +} + + +/*======================================================* + * See sfuntmpl_doc.c for the optional S-function methods * + *======================================================*/ + +/*=============================* + * Required S-function trailer * + *=============================*/ + +#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ +#include "simulink.c" /* MEX-file interface mechanism */ +#else +#include "cg_sfun.h" /* Code generation registration function */ +#endif diff --git a/sfAnalogOutput.mexa64 b/sfAnalogOutput.mexa64 new file mode 100755 index 0000000..718991a Binary files /dev/null and b/sfAnalogOutput.mexa64 differ diff --git a/sfuntmpl_basic.c b/sfuntmpl_basic.c new file mode 100644 index 0000000..13a0d8b --- /dev/null +++ b/sfuntmpl_basic.c @@ -0,0 +1,221 @@ +/* + * sfuntmpl_basic.c: Basic 'C' template for a level 2 S-function. + * + * ------------------------------------------------------------------------- + * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | + * ------------------------------------------------------------------------- + * + * Copyright 1990-2002 The MathWorks, Inc. + * $Revision: 1.27.4.2 $ + */ + + +/* + * You must specify the S_FUNCTION_NAME as the name of your S-function + * (i.e. replace sfuntmpl_basic with the name of your S-function). + */ + +#define S_FUNCTION_NAME sfuntmpl_basic +#define S_FUNCTION_LEVEL 2 + +/* + * Need to include simstruc.h for the definition of the SimStruct and + * its associated macro definitions. + */ +#include "simstruc.h" + + + +/* Error handling + * -------------- + * + * You should use the following technique to report errors encountered within + * an S-function: + * + * ssSetErrorStatus(S,"Error encountered due to ..."); + * return; + * + * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. + * It cannot be a local variable. For example the following will cause + * unpredictable errors: + * + * mdlOutputs() + * { + * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} + * sprintf(msg,"Error due to %s", string); + * ssSetErrorStatus(S,msg); + * return; + * } + * + * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. + */ + +/*====================* + * S-function methods * + *====================*/ + +/* Function: mdlInitializeSizes =============================================== + * Abstract: + * The sizes information is used by Simulink to determine the S-function + * block's characteristics (number of inputs, outputs, states, etc.). + */ +static void mdlInitializeSizes(SimStruct *S) +{ + /* See sfuntmpl_doc.c for more details on the macros below */ + + ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ + if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { + /* Return if number of expected != number of actual parameters */ + return; + } + + ssSetNumContStates(S, 0); + ssSetNumDiscStates(S, 0); + + if (!ssSetNumInputPorts(S, 1)) return; + ssSetInputPortWidth(S, 0, 1); + ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ + /* + * Set direct feedthrough flag (1=yes, 0=no). + * A port has direct feedthrough if the input is used in either + * the mdlOutputs or mdlGetTimeOfNextVarHit functions. + * See matlabroot/simulink/src/sfuntmpl_directfeed.txt. + */ + ssSetInputPortDirectFeedThrough(S, 0, 1); + + if (!ssSetNumOutputPorts(S, 1)) return; + ssSetOutputPortWidth(S, 0, 1); + + ssSetNumSampleTimes(S, 1); + ssSetNumRWork(S, 0); + ssSetNumIWork(S, 0); + ssSetNumPWork(S, 0); + ssSetNumModes(S, 0); + ssSetNumNonsampledZCs(S, 0); + + /* Specify the sim state compliance to be same as a built-in block */ + ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); + + ssSetOptions(S, 0); +} + + + +/* Function: mdlInitializeSampleTimes ========================================= + * Abstract: + * This function is used to specify the sample time(s) for your + * S-function. You must register the same number of sample times as + * specified in ssSetNumSampleTimes. + */ +static void mdlInitializeSampleTimes(SimStruct *S) +{ + ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); + ssSetOffsetTime(S, 0, 0.0); + +} + + + +#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ +#if defined(MDL_INITIALIZE_CONDITIONS) + /* Function: mdlInitializeConditions ======================================== + * Abstract: + * In this function, you should initialize the continuous and discrete + * states for your S-function block. The initial states are placed + * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). + * You can also perform any other initialization activities that your + * S-function may require. Note, this routine will be called at the + * start of simulation and if it is present in an enabled subsystem + * configured to reset states, it will be call when the enabled subsystem + * restarts execution to reset the states. + */ + static void mdlInitializeConditions(SimStruct *S) + { + } +#endif /* MDL_INITIALIZE_CONDITIONS */ + + + +#define MDL_START /* Change to #undef to remove function */ +#if defined(MDL_START) + /* Function: mdlStart ======================================================= + * Abstract: + * This function is called once at start of model execution. If you + * have states that should be initialized once, this is the place + * to do it. + */ + static void mdlStart(SimStruct *S) + { + } +#endif /* MDL_START */ + + + +/* Function: mdlOutputs ======================================================= + * Abstract: + * In this function, you compute the outputs of your S-function + * block. + */ +static void mdlOutputs(SimStruct *S, int_T tid) +{ + const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); + real_T *y = ssGetOutputPortSignal(S,0); + y[0] = u[0]; +} + + + +#define MDL_UPDATE /* Change to #undef to remove function */ +#if defined(MDL_UPDATE) + /* Function: mdlUpdate ====================================================== + * Abstract: + * This function is called once for every major integration time step. + * Discrete states are typically updated here, but this function is useful + * for performing any tasks that should only take place once per + * integration step. + */ + static void mdlUpdate(SimStruct *S, int_T tid) + { + } +#endif /* MDL_UPDATE */ + + + +#define MDL_DERIVATIVES /* Change to #undef to remove function */ +#if defined(MDL_DERIVATIVES) + /* Function: mdlDerivatives ================================================= + * Abstract: + * In this function, you compute the S-function block's derivatives. + * The derivatives are placed in the derivative vector, ssGetdX(S). + */ + static void mdlDerivatives(SimStruct *S) + { + } +#endif /* MDL_DERIVATIVES */ + + + +/* Function: mdlTerminate ===================================================== + * Abstract: + * In this function, you should perform any actions that are necessary + * at the termination of a simulation. For example, if memory was + * allocated in mdlStart, this is the place to free it. + */ +static void mdlTerminate(SimStruct *S) +{ +} + + +/*======================================================* + * See sfuntmpl_doc.c for the optional S-function methods * + *======================================================*/ + +/*=============================* + * Required S-function trailer * + *=============================*/ + +#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ +#include "simulink.c" /* MEX-file interface mechanism */ +#else +#include "cg_sfun.h" /* Code generation registration function */ +#endif diff --git a/slprj/ert/test/tmwinternal/minfo.mat b/slprj/ert/test/tmwinternal/minfo.mat new file mode 100644 index 0000000..a86ab52 Binary files /dev/null and b/slprj/ert/test/tmwinternal/minfo.mat differ diff --git a/slprj/sl_proj.tmw b/slprj/sl_proj.tmw new file mode 100644 index 0000000..5e270e4 --- /dev/null +++ b/slprj/sl_proj.tmw @@ -0,0 +1,2 @@ +Simulink Coder project marker file. Please don't change it. +slprjVersion: 8.0_41_001 \ No newline at end of file diff --git a/test b/test new file mode 100755 index 0000000..f093376 Binary files /dev/null and b/test differ diff --git a/test.mat b/test.mat new file mode 100644 index 0000000..63b3204 Binary files /dev/null and b/test.mat differ diff --git a/test.slx b/test.slx new file mode 100644 index 0000000..f24cf97 Binary files /dev/null and b/test.slx differ diff --git a/test_ert_rtw/build_exception.mat b/test_ert_rtw/build_exception.mat new file mode 100644 index 0000000..52f0a7e Binary files /dev/null and b/test_ert_rtw/build_exception.mat differ