--- /dev/null
+/*
+ * 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;
+}*/
--- /dev/null
+/*
+ * 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;
+}*/
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * (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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+Simulink Coder project marker file. Please don't change it.
+slprjVersion: 8.0_41_001
\ No newline at end of file