]> rtime.felk.cvut.cz Git - mf624-simulink.git/commitdiff
First version of s-functions needed for opertaing mf624.
authorkrecmich <krecmich@emotor.felk.cvut.cz>
Mon, 10 Jun 2013 10:21:12 +0000 (12:21 +0200)
committerkrecmich <krecmich@emotor.felk.cvut.cz>
Mon, 10 Jun 2013 10:21:12 +0000 (12:21 +0200)
Signed-off-by: krecmich <krecmich@emotor.felk.cvut.cz>
16 files changed:
mf624.c [new file with mode: 0644]
mf624.c~ [new file with mode: 0644]
mf624.h [new file with mode: 0644]
mf624.h~ [new file with mode: 0644]
mf624.mexa64 [new file with mode: 0755]
sfAnalogInput.c [new file with mode: 0644]
sfAnalogInput.mexa64 [new file with mode: 0755]
sfAnalogOutput.c [new file with mode: 0644]
sfAnalogOutput.mexa64 [new file with mode: 0755]
sfuntmpl_basic.c [new file with mode: 0644]
slprj/ert/test/tmwinternal/minfo.mat [new file with mode: 0644]
slprj/sl_proj.tmw [new file with mode: 0644]
test [new file with mode: 0755]
test.mat [new file with mode: 0644]
test.slx [new file with mode: 0644]
test_ert_rtw/build_exception.mat [new file with mode: 0644]

diff --git a/mf624.c b/mf624.c
new file mode 100644 (file)
index 0000000..2575756
--- /dev/null
+++ b/mf624.c
@@ -0,0 +1,530 @@
+/* 
+ * Application using MF624 UIO driver
+ * 
+ * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com> 
+ * 
+ * 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 <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stdint.h> // uintX_t
+#include <inttypes.h>
+#include <unistd.h>
+#include <alloca.h>
+
+#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 (file)
index 0000000..6ce3d5b
--- /dev/null
+++ b/mf624.c~
@@ -0,0 +1,530 @@
+/* 
+ * Application using MF624 UIO driver
+ * 
+ * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com> 
+ * 
+ * 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 <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stdint.h> // uintX_t
+#include <inttypes.h>
+#include <unistd.h>
+#include <alloca.h>
+
+#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 (file)
index 0000000..b574765
--- /dev/null
+++ b/mf624.h
@@ -0,0 +1,82 @@
+#ifndef MF624
+#define MF624
+
+#include <sys/types.h>
+#include <stdint.h> // uintX_t
+#include <inttypes.h>
+
+
+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 (file)
index 0000000..13a2739
--- /dev/null
+++ b/mf624.h~
@@ -0,0 +1,80 @@
+#ifndef MF624
+#define MF624
+
+#include <sys/types.h>
+#include <stdint.h> // uintX_t
+#include <inttypes.h>
+
+
+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 (executable)
index 0000000..c675168
Binary files /dev/null and b/mf624.mexa64 differ
diff --git a/sfAnalogInput.c b/sfAnalogInput.c
new file mode 100644 (file)
index 0000000..bfee43a
--- /dev/null
@@ -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 (executable)
index 0000000..3cc9ff9
Binary files /dev/null and b/sfAnalogInput.mexa64 differ
diff --git a/sfAnalogOutput.c b/sfAnalogOutput.c
new file mode 100644 (file)
index 0000000..a3fa03d
--- /dev/null
@@ -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 (executable)
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 (file)
index 0000000..13a0d8b
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..5e270e4
--- /dev/null
@@ -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 (executable)
index 0000000..f093376
Binary files /dev/null and b/test differ
diff --git a/test.mat b/test.mat
new file mode 100644 (file)
index 0000000..63b3204
Binary files /dev/null and b/test.mat differ
diff --git a/test.slx b/test.slx
new file mode 100644 (file)
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 (file)
index 0000000..52f0a7e
Binary files /dev/null and b/test_ert_rtw/build_exception.mat differ