]> rtime.felk.cvut.cz Git - mf624-simulink.git/blobdiff - mf624_SIMULINK.c
Include license header to prepare code for publication.
[mf624-simulink.git] / mf624_SIMULINK.c
index 03c1a50759681a048421e70be6cf9c0169a2c951..94c3e0463854926f3f2722bc157874563097f552 100644 (file)
@@ -1,21 +1,35 @@
-/* 
- * 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.
+/*
+ * Common Humusoft MF624 card Simulink code for use with Linux UIO driver
  *
- * 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.
+ * Copyright (C) 2011-2014 Rostislav Lisovy <lisovy@gmail.com>
+ * Copyright (C) 2013 Michal Kreč <krecmich@fel.cvut.cz>
+ * Copyright (C) 2013 Michal Sojka <sojkam1@fel.cvut.cz>
  *
- * 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.
+ * Department of Control Engineering
+ * Faculty of Electrical Engineering
+ * Czech Technical University in Prague (CTU)
+ *
+ * The ERT Linux support code can be distributed in compliance
+ * with GNU General Public License (GPL) version 2 or later.
+ * Other licence can negotiated with CTU.
+ *
+ * Next exception is granted in addition to GPL.
+ * Instantiating or linking compiled version of this code
+ * to produce an application image/executable, does not
+ * by itself cause the resulting application image/executable
+ * to be covered by the GNU General Public License.
+ * This exception does not however invalidate any other reasons
+ * why the executable file might be covered by the GNU Public License.
+ * Publication of enhanced or derived S-function files is required
+ * although.
+ *
+ * Linux ERT code is available from
+ *    http://rtime.felk.cvut.cz/gitweb/ert_linux.git
+ * More CTU Linux target for Simulink components are available at
+ *    http://lintarget.sourceforge.net/
+ *
+ * sfuntmpl_basic.c by The MathWorks, Inc. has been used to accomplish
+ * required S-function structure.
  */
 
 #include <stdio.h>
 #include <inttypes.h>
 #include <unistd.h>
 #include <alloca.h>
+#include <stdlib.h>
 
 #include "mf624_SIMULINK.h"
 
 /****************************************************************/
 
 
-int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
+/* Which uio device node to use */
+#define UIO "uio0"
+
+mf624_state_t* mfst=NULL;
+unsigned mfst_refcnt = 0;
+
+static int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
 {
        FILE *file;
        void *s;
@@ -81,7 +102,7 @@ int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
        return 0;
 }
 
-int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
+static int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
 {
        static size_t page_mask = 0;
        off_t mmap_start;
@@ -105,6 +126,19 @@ int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
        return 0;
 }
 
+static int bar_mapping_destroy(bar_mapping_t *barmap)
+{
+       off_t mmap_start;
+        size_t mmap_size;
+       size_t 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;
+
+       return munmap(barmap->mmap_addr, mmap_size);
+}
+
 /****************************************************************/
 
 #define BUFF_SMALL             32
@@ -114,35 +148,11 @@ int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
 
 
 
-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,
-};
-
-
-
 
 mf624_state_t mf624_state;
 
 /* Print one byte as binary number */
-void print_8bin(int nr)
+static void print_8bin(int nr)
 {
        int i;
        for (i = 7; i >= 0; i--) {
@@ -173,7 +183,7 @@ void DAC_enable(mf624_state_t* mfst)
                MFST2REG(mfst, 0, GPIOC_reg));
 }
 
-                            
+
 
 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
 {
@@ -210,7 +220,7 @@ double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
        mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
 
        // Check if conversion has finished
-       while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { 
+       while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) {
                for (i = 0; i < 1000; i++) {} // small wait
        }
 
@@ -220,25 +230,35 @@ double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
        return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
 }
 
+extern uint32_t IRC_mode_change(mf624_state_t* mfst, uint32_t change_mask, uint32_t change_val)
+{
+       /* This sequence should be protected by mutex to protect changes in multirate systems */
+       mfst->IRC_mode = (mfst->IRC_mode & ~change_mask) | (change_val & change_mask);
+       mf624_write32(mfst->IRC_mode, MFST2REG(mfst, 4, IRCCTRL_reg));
+        /*printf("change_mask 0x%08x, change_val 0x%08x\n", change_mask, change_val);*/
+        /*printf("IRC mode set to %08lx\n", mfst->IRC_mode);*/
+       return mfst->IRC_mode;
+}
+
 
-int open_device(char* path) {
+static int open_device(char* path) {
        int device_fd;
 
        device_fd = open(path, O_RDWR | O_SYNC);
        if (device_fd == -1) {
-               perror("open()");
+               perror(path);
                return -1;
        }
 
        return device_fd;
 }
 
-void wait_for_interrupts(int device_fd)
+static void wait_for_interrupts(int device_fd)
 {
        read(device_fd, NULL, 1);
 }
 
-int disable_interrupts(int device_fd)
+static int disable_interrupts(int device_fd)
 {
        uint32_t control_value = 0;
        int status;
@@ -252,7 +272,7 @@ int disable_interrupts(int device_fd)
        return status;
 }
 
-int enable_interrupts(int device_fd)
+static int enable_interrupts(int device_fd)
 {
        uint32_t control_value = 1;
        int status;
@@ -266,7 +286,7 @@ int enable_interrupts(int device_fd)
        return status;
 }
 
-void list_available_mem_regions(char* device)
+static void list_available_mem_regions(char* device)
 {
        int status;
        char path[] = "/sys/class/uio/";
@@ -302,7 +322,7 @@ void list_available_mem_regions(char* device)
 }
 
 
-void list_available_io_ports(char *device)
+static void list_available_io_ports(char *device)
 {
        int status;
        char path[] = "/sys/class/uio/";
@@ -344,7 +364,7 @@ void list_available_io_ports(char *device)
 }
 
 
-void run_simple_tests(char* dev_name)
+static void run_simple_tests(char* dev_name)
 {
        int status;
        int device_fd;
@@ -363,7 +383,7 @@ void run_simple_tests(char* dev_name)
                if (status != -1) {
                        printf(" Probably OK\n");
                }
-       
+
                printf("Tring to disable interrupts\n");
                status = disable_interrupts(device_fd);
                if (status != -1) {
@@ -379,7 +399,7 @@ void run_simple_tests(char* dev_name)
        list_available_io_ports(dev_name);
 }
 
-int mmap_regions(mf624_state_t* mfst)
+static 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);
@@ -425,6 +445,80 @@ int mmap_regions(mf624_state_t* mfst)
 }
 
 
+
+/**
+ * Try to initialize the MF624 UIO driver.
+ *
+ * If and only if S is not NULL and initialization fails, then
+ * ssSetErrorStatus() gets called to report the error via Simulink
+ * interface.
+ *
+ * @param S Pointer to SimStruct for error reporting or NULL.
+ *
+ * @return Zero in case of success, -1 in case of error.
+ */
+int mf624_init(SimStruct *S)
+{
+       if (mfst==NULL) {
+               mfst = malloc(sizeof(mf624_state_t));
+               char fn[32];
+               mfst->uio_dev = UIO;
+               snprintf(fn, sizeof(fn), "/dev/%s", mfst->uio_dev);
+
+               mfst->device_fd = open_device(fn);
+               if (mfst->device_fd < 0) {
+                       if (S) ssSetErrorStatus(S,"/dev/" UIO ": open failed");
+                       goto free;
+               }
+               if (mmap_regions(mfst) < 0) {
+                       if (S) ssSetErrorStatus(S,"/dev/" UIO ": mmap_regions failed");
+                       goto close;
+               }
+       }
+       mfst_refcnt++;
+       return 0;
+close:
+       close(mfst->device_fd);
+free:
+       free(mfst);
+       mfst = NULL;
+       return -1;
+}
+
+int mf624_done()
+{
+       if (mfst) {
+               if (--mfst_refcnt == 0) {
+                       close(mfst->device_fd);
+                       bar_mapping_destroy(&mfst->bar0);
+                       bar_mapping_destroy(&mfst->bar2);
+                       bar_mapping_destroy(&mfst->bar4);
+                       free(mfst);
+                       mfst = NULL;
+               }
+       }
+
+       return 0;
+}
+
+
+/**
+ * Check whether MF624 card is initialized.
+ *
+ * @param S
+ *
+ * @return Zero if MF624 is initialized, -1 othewise.
+ */
+int mf624_check(SimStruct *S)
+{
+       if (mfst==NULL) {
+               if (S) ssSetErrorStatus(S, "MF624 is not initialized");
+               return -1;
+       }
+       else
+               return 0;
+}
+
 /*int main(int argc, char* argv[])
 {
        mf624_state_t* mfst = &mf624_state;
@@ -481,7 +575,7 @@ int mmap_regions(mf624_state_t* mfst)
                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);