]> rtime.felk.cvut.cz Git - mf624-simulink.git/blob - mf624_SIMULINK.c
Improve error/warning message
[mf624-simulink.git] / mf624_SIMULINK.c
1 /* 
2  * Application using MF624 UIO driver
3  * 
4  * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com> 
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <stdio.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <dirent.h>
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 #include <stdint.h> // uintX_t
31 #include <inttypes.h>
32 #include <unistd.h>
33 #include <alloca.h>
34
35 #include "mf624_SIMULINK.h"
36
37 /****************************************************************/
38
39
40 #include "simstruc.h"
41
42 /* Which uio device node to use */
43 #define UIO "uio0"
44
45 mf624_state_t* mfst=NULL;
46
47 int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
48 {
49         FILE *file;
50         void *s;
51         int ssiz;
52         static size_t page_size;
53
54         page_size = sysconf(_SC_PAGESIZE);
55
56         ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
57         if (ssiz < 0)
58                 return -1;
59         /* add reserve to store each size addr, name, offset, size */
60         ssiz += 6 + 1;
61         s = alloca(ssiz);
62
63         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
64         file = fopen(s, "rb");
65         if (file == NULL)
66           return -1;
67         fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
68         fclose(file);
69
70         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
71         file = fopen(s, "rb");
72         if (file == NULL) {
73                 barmap->offset = barmap->phys_addr & (page_size - 1);
74         } else {
75                 fscanf(file, "%"SCNi32, &barmap->offset);
76                 fclose(file);
77         }
78
79         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
80         file = fopen(s, "rb");
81         if (file == NULL)
82           return -1;
83         fscanf(file, "%"SCNi32, &barmap->size);
84         fclose(file);
85
86         barmap->mmap_offset = page_size * map_nr + barmap->offset;
87
88         return 0;
89 }
90
91 int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
92 {
93         static size_t page_mask = 0;
94         off_t mmap_start;
95         size_t mmap_size;
96
97         if (!page_mask)
98                  page_mask = sysconf(_SC_PAGESIZE) - 1;
99
100         mmap_start = barmap->mmap_offset & ~page_mask;
101         mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
102         mmap_size &= ~page_mask;
103
104         barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start);
105         if (barmap->mmap_addr == MAP_FAILED) {
106                 return -1;
107         }
108
109         barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
110         barmap->virt_addr += barmap->mmap_offset & page_mask;
111
112         return 0;
113 }
114
115 /****************************************************************/
116
117 #define BUFF_SMALL              32
118 #define BUFF_MID                256
119 #define min(a, b)               ((a) > (b) ? (b) : (a))
120
121
122
123
124
125 mf624_state_t mf624_state;
126
127 /* Print one byte as binary number */
128 void print_8bin(int nr)
129 {
130         int i;
131         for (i = 7; i >= 0; i--) {
132                 printf("%d" , ((nr & (1 << i)) > 0));
133         }
134
135         printf("\n");
136 }
137
138
139
140 void DIO_write(mf624_state_t* mfst, int16_t val)
141 {
142         mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
143 }
144
145 uint16_t DIO_read(mf624_state_t* mfst)
146 {
147         return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
148 }
149
150 void DAC_enable(mf624_state_t* mfst)
151 {
152         // Setting DACEN and LDAC bits in GPIO register influences all DACs
153         mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
154                 | GPIOC_DACEN_mask) // enable output
155                 & ~GPIOC_LDAC_mask, // enable conversion
156                 MFST2REG(mfst, 0, GPIOC_reg));
157 }
158
159                             
160
161 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
162 {
163         if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
164                 return -1;
165
166         mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
167         return 0;
168 }
169
170 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
171 {
172         mfst->ADC_enabled = 0;
173
174         if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
175                 return -1;
176
177         mfst->ADC_enabled = (1 << channel);
178
179         mfst->ADC_enabled &= 0xFF;
180         mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
181         //print_8bin(ADC_enabled);
182
183         return 0;
184 }
185
186 /* This function blocks until conversion is finished */
187 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
188 {
189         volatile int i;
190         int result;
191
192         // Activate trigger to start conversion
193         mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
194
195         // Check if conversion has finished
196         while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { 
197                 for (i = 0; i < 1000; i++) {} // small wait
198         }
199
200         ADC_enable(mfst, channel);
201         result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
202
203         return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
204 }
205
206
207 int open_device(char* path) {
208         int device_fd;
209
210         device_fd = open(path, O_RDWR | O_SYNC);
211         if (device_fd == -1) {
212                 perror(path);
213                 return -1;
214         }
215
216         return device_fd;
217 }
218
219 void wait_for_interrupts(int device_fd)
220 {
221         read(device_fd, NULL, 1);
222 }
223
224 int disable_interrupts(int device_fd)
225 {
226         uint32_t control_value = 0;
227         int status;
228
229         status = write(device_fd, &control_value, sizeof(uint32_t));
230         if (status == -1) {
231                 perror("write()");
232                 return -1;
233         }
234
235         return status;
236 }
237
238 int enable_interrupts(int device_fd)
239 {
240         uint32_t control_value = 1;
241         int status;
242
243         status = write(device_fd, &control_value, sizeof(uint32_t));
244         if (status == -1) {
245                 perror("write()");
246                 return -1;
247         }
248
249         return status;
250 }
251
252 void list_available_mem_regions(char* device)
253 {
254         int status;
255         char path[] = "/sys/class/uio/";
256         char subdir[] = "/maps/";
257         char directory[BUFF_MID];
258         memset(directory, '\0', BUFF_MID);
259
260         DIR *dip;
261         struct dirent *dit;
262
263         strncat(directory, path, strlen(path));
264         strncat(directory, device, min(strlen(device), 8));
265         strncat(directory, subdir, strlen(subdir));
266
267         dip = opendir(directory);
268         if (dip == NULL) {
269                 perror("opendir");
270                 return;
271         }
272
273         while ((dit = readdir(dip)) != NULL) {
274                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
275                         printf(" %s\n", dit->d_name);
276                 }
277         }
278
279         status = closedir(dip);
280         if (status == -1) {
281                 perror("closedir()");
282                 return;
283         }
284
285 }
286
287
288 void list_available_io_ports(char *device)
289 {
290         int status;
291         char path[] = "/sys/class/uio/";
292         char subdir[] = "/portio/";
293         char directory[BUFF_MID];
294         memset(directory, '\0', BUFF_MID);
295
296         DIR *dip;
297         struct dirent *dit;
298
299         strncat(directory, path, strlen(path));
300         strncat(directory, device, min(strlen(device), 8));
301         strncat(directory, subdir, strlen(subdir));
302
303         status = access(directory, F_OK);
304         if (status == -1) {
305                 printf(" There are no IO port available\n");
306                 return;
307         }
308
309         dip = opendir(directory);
310         if (dip == NULL) {
311                 perror("opendir");
312                 return;
313         }
314
315         while ((dit = readdir(dip)) != NULL) {
316                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
317                         printf(" %s\n", dit->d_name);
318                 }
319         }
320
321         status = closedir(dip);
322         if (status == -1) {
323                 perror("closedir()");
324                 return;
325         }
326
327 }
328
329
330 void run_simple_tests(char* dev_name)
331 {
332         int status;
333         int device_fd;
334         char buff[BUFF_SMALL];
335         memset(buff, '\0', BUFF_SMALL);
336
337         strncat(buff, "/dev/", 5);
338         strncat(buff, dev_name, min(strlen(dev_name), 8));
339
340         printf("Opening %s\n", buff);
341
342         device_fd = open_device(buff);
343         if (device_fd != -1) {
344                 printf("Tring to enable interrupts\n");
345                 status = enable_interrupts(device_fd);
346                 if (status != -1) {
347                         printf(" Probably OK\n");
348                 }
349         
350                 printf("Tring to disable interrupts\n");
351                 status = disable_interrupts(device_fd);
352                 if (status != -1) {
353                         printf(" Probably OK\n");
354                 }
355         }
356
357
358         printf("Checking for available memory regions exported by the UIO driver\n");
359         list_available_mem_regions(dev_name);
360
361         printf("Checking for available IO ports exported by the UIO driver\n");
362         list_available_io_ports(dev_name);
363 }
364
365 int mmap_regions(mf624_state_t* mfst)
366 {
367         if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
368                 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
369                 return -1;
370         }
371
372         if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
373                 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
374                 return -1;
375         }
376
377         if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
378                 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
379                 return -1;
380         }
381
382         if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
383                 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
384                 return -1;
385         }
386
387         if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
388                 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
389                 return -1;
390         }
391
392         if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
393                 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
394                 return -1;
395         }
396
397 #if 1
398         printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
399         printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
400         printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
401
402         printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
403         printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
404         printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
405 #endif
406
407         return 0;
408 }
409
410
411
412 /** 
413  * Try to initialize the MF624 UIO driver.
414  *
415  * If and only if S is not NULL and initialization fails, then
416  * ssSetErrorStatus() gets called to report the error via Simulink
417  * interface.
418  * 
419  * @param S Pointer to SimStruct for error reporting or NULL.
420  * 
421  * @return Zero in case of success, -1 in case of error.
422  */
423 int mf624_init(SimStruct *S)
424 {
425         if (mfst==NULL) {
426                 mfst = malloc(sizeof(mf624_state_t));
427                 char fn[32];
428                 mfst->uio_dev = UIO;
429                 snprintf(fn, sizeof(fn), "/dev/%s", mfst->uio_dev);
430
431                 mfst->device_fd = open_device(fn);
432                 if (mfst->device_fd < 0) {
433                         if (S) ssSetErrorStatus(S,"/dev/" UIO ": open failed");
434                         goto free;
435                 }
436                 if (mmap_regions(mfst) < 0) {
437                         if (S) ssSetErrorStatus(S,"/dev/" UIO ": mmap_regions failed");
438                         goto close;
439                 }
440
441         }
442         return 0;
443 close:
444         close(mfst->device_fd);
445 free:
446         free(mfst);
447         mfst = NULL;
448         return -1;
449 }
450
451 /*int main(int argc, char* argv[])
452 {
453         mf624_state_t* mfst = &mf624_state;
454         char buff[BUFF_SMALL];
455         memset(buff, '\0', BUFF_SMALL);
456
457         if (argc < 2) {
458                 printf("Usage: %s UIO_DEVICE\n   UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
459                 return 1;
460         }
461
462         mfst->uio_dev = argv[1];
463
464         strncat(buff, "/dev/", 5);
465         strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
466
467         mfst->device_fd = open_device(buff);
468         if (mfst->device_fd < 0) {
469                 fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
470                 return 2;
471         }
472         if (mmap_regions(mfst) < 0) {
473                 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
474                 return 2;
475         }
476
477         DAC_enable(mfst);
478
479         while (1){
480                 printf("Reading DIO: ");
481                 print_8bin(DIO_read(mfst));
482                 sleep(1);
483
484                 printf("Setting DA1 to 10 V\n");
485                 DAC_write(mfst, DA1, 0x3FFF);
486                 sleep(1);
487
488                 printf("Reading ADC0: ");
489                 printf("%f V\n", ADC_read(mfst, AD0));
490                 sleep(1);
491
492                 printf("Reading ADC1: ");
493                 printf("%f V\n", ADC_read(mfst, AD1));
494                 sleep(1);
495
496                 printf("Setting DIO to 0xff\n");
497                 DIO_write(mfst, 0xff);
498                 sleep(1);
499
500                 printf("Setting DIO to 0x00\n");
501                 DIO_write(mfst, 0x00);
502                 sleep(1);
503
504                 printf("Setting DA1 to 5 V\n");
505                 DAC_write(mfst, DA1, 0x3000);
506                 sleep(1);
507                 
508                 printf("Reading ADC0: ");
509                 printf("%f V\n", ADC_read(mfst, AD0));
510                 sleep(1);
511
512                 printf("Reading ADC1: ");
513                 printf("%f V\n", ADC_read(mfst, AD1));
514                 sleep(1);
515                 printf("----------------------\n\n");
516         }
517
518
519         return 0;
520 }*/