]> rtime.felk.cvut.cz Git - mf6xx.git/blob - src/uio/mf624/userspace/test_application/main.c
Do not allocate extra bytes for path in the mf624 UIO test.
[mf6xx.git] / src / uio / mf624 / userspace / test_application / main.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 /****************************************************************/
36
37 typedef struct bar_mapping_t {
38         uintptr_t virt_addr;
39         void *    mmap_addr;
40         off_t     mmap_offset;
41         uintptr_t phys_addr;
42         uint32_t  size;
43         uint32_t  offset;
44 } bar_mapping_t;
45
46 int bar_mapping_fill(bar_mapping_t *barmap, const char *uio_dev, int map_nr)
47 {
48         FILE *file;
49         void *s;
50         int ssiz;
51         static size_t page_size;
52
53         page_size = sysconf(_SC_PAGESIZE);
54
55         ssiz = snprintf(NULL, 0, "/sys/class/uio/%s/maps/map%i/", uio_dev, map_nr);
56         if (ssiz < 0)
57                 return -1;
58         /* add reserve to store each size addr, name, offset, size */
59         ssiz += 6 + 1;
60         s = alloca(ssiz);
61
62         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/addr", uio_dev, map_nr);
63         file = fopen(s, "rb");
64         if (file == NULL)
65           return -1;
66         fscanf(file, "%"SCNiPTR, &barmap->phys_addr);
67         fclose(file);
68
69         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/offset", uio_dev, map_nr);
70         file = fopen(s, "rb");
71         if (file == NULL) {
72                 barmap->offset = barmap->phys_addr & (page_size - 1);
73         } else {
74                 fscanf(file, "%"SCNi32, &barmap->offset);
75                 fclose(file);
76         }
77
78         snprintf(s, ssiz, "/sys/class/uio/%s/maps/map%i/size", uio_dev, map_nr);
79         file = fopen(s, "rb");
80         if (file == NULL)
81           return -1;
82         fscanf(file, "%"SCNi32, &barmap->size);
83         fclose(file);
84
85         barmap->mmap_offset = page_size * map_nr + barmap->offset;
86
87         return 0;
88 }
89
90 int bar_mapping_setup(bar_mapping_t *barmap, int device_fd)
91 {
92         static size_t page_mask = 0;
93         off_t mmap_start;
94         size_t mmap_size;
95
96         if (!page_mask)
97                  page_mask = sysconf(_SC_PAGESIZE) - 1;
98
99         mmap_start = barmap->mmap_offset & ~page_mask;
100         mmap_size = barmap->mmap_offset + barmap->size + page_mask - mmap_start;
101         mmap_size &= ~page_mask;
102
103         barmap->mmap_addr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, device_fd, mmap_start);
104         if (barmap->mmap_addr == MAP_FAILED) {
105                 return -1;
106         }
107
108         barmap->virt_addr = (uintptr_t)barmap->mmap_addr;
109         barmap->virt_addr += barmap->mmap_offset & page_mask;
110
111         return 0;
112 }
113
114 /****************************************************************/
115
116 #define BUFF_SMALL              32
117 #define BUFF_MID                256
118 #define min(a, b)               ((a) > (b) ? (b) : (a))
119
120 /* Hardware specific */
121 /* BAR0 */
122 #define GPIOC_reg               0x54
123
124 /* BAR2 */
125 #define ADCTRL_reg              0x00
126 #define ADDATA0_reg             0x00
127 #define ADDATA1_reg             0x02
128 #define ADDATA2_reg             0x04
129 #define ADDATA3_reg             0x06
130 #define ADDATA4_reg             0x08
131 #define ADDATA5_reg             0x0a
132 #define ADDATA6_reg             0x0c
133 #define ADDATA7_reg             0x0e
134 #define ADSTART_reg             0x20
135
136 #define DOUT_reg                0x10
137 #define DIN_reg                 0x10
138 #define DA0_reg                 0x20
139 #define DA1_reg                 0x22
140 #define DA2_reg                 0x24
141 #define DA3_reg                 0x26
142 #define DA4_reg                 0x28
143 #define DA5_reg                 0x2A
144 #define DA6_reg                 0x2C
145 #define DA7_reg                 0x2E
146
147 #define GPIOC_DACEN_mask        (1 << 26)
148 #define GPIOC_LDAC_mask         (1 << 23)
149 #define GPIOC_EOLC_mask         (1 << 17)
150
151
152 typedef enum {DA0, DA1, DA2, DA3, DA4, DA5, DA6, DA7} dac_channel_t;
153 typedef enum {AD0, AD1, AD2, AD3, AD4, AD5, AD6, AD7} adc_channel_t;
154
155 static uint32_t dac_channel2reg[] = {
156         [DA0] = DA0_reg,
157         [DA1] = DA1_reg,
158         [DA2] = DA2_reg,
159         [DA3] = DA3_reg,
160         [DA4] = DA4_reg,
161         [DA5] = DA5_reg,
162         [DA6] = DA6_reg,
163         [DA7] = DA7_reg,
164 };
165
166 static uint32_t adc_channel2reg[] = {
167         [AD0] = ADDATA0_reg,
168         [AD1] = ADDATA1_reg,
169         [AD2] = ADDATA2_reg,
170         [AD3] = ADDATA3_reg,
171         [AD4] = ADDATA4_reg,
172         [AD5] = ADDATA5_reg,
173         [AD6] = ADDATA6_reg,
174         [AD7] = ADDATA7_reg,
175 };
176
177 typedef struct mf624_state_t {
178         int device_fd;
179         char *uio_dev;
180         bar_mapping_t bar0;
181         bar_mapping_t bar2;
182         bar_mapping_t bar4;
183         int status;
184         int ADC_enabled; // Which ADCs are enabled
185 } mf624_state_t;
186
187 #define MFST2REG(mfst, bar_num, reg_offs) \
188         ((void *)(mfst->bar##bar_num.virt_addr + (reg_offs)))
189
190 mf624_state_t mf624_state;
191
192 /* Print one byte as binary number */
193 void print_8bin(int nr)
194 {
195         int i;
196         for (i = 7; i >= 0; i--) {
197                 printf("%d" , ((nr & (1 << i)) > 0));
198         }
199
200         printf("\n");
201 }
202
203 static inline int16_t mf624_read16(void *ptr)
204 {
205         return *(volatile uint16_t*)ptr;
206 }
207 static inline int32_t mf624_read32(void *ptr)
208 {
209         return *(volatile uint32_t*) ptr;
210 }
211
212 static inline void mf624_write16(uint16_t val, void *ptr)
213 {
214         *(volatile uint16_t*) ptr = val;
215 }
216
217 static inline void mf624_write32(uint32_t val, void *ptr)
218 {
219         *(volatile uint32_t*) ptr = val;
220 }
221
222 void DIO_write(mf624_state_t* mfst, int16_t val)
223 {
224         mf624_write16(val, MFST2REG(mfst, 2, DOUT_reg));
225 }
226
227 uint16_t DIO_read(mf624_state_t* mfst)
228 {
229         return mf624_read16(MFST2REG(mfst, 2, DIN_reg)) & 0xFF;
230 }
231
232 void DAC_enable(mf624_state_t* mfst)
233 {
234         // Setting DACEN and LDAC bits in GPIO register influences all DACs
235         mf624_write32((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg))
236                 | GPIOC_DACEN_mask) // enable output
237                 & ~GPIOC_LDAC_mask, // enable conversion
238                 MFST2REG(mfst, 0, GPIOC_reg));
239 }
240
241 int DAC_write(mf624_state_t* mfst, dac_channel_t channel, int val)
242 {
243         if (channel > sizeof(dac_channel2reg)/sizeof(*dac_channel2reg))
244                 return -1;
245
246         mf624_write16(val, MFST2REG(mfst, 2, dac_channel2reg[channel]));
247         return 0;
248 }
249
250 int ADC_enable(mf624_state_t* mfst, adc_channel_t channel)
251 {
252         mfst->ADC_enabled = 0;
253
254         if (channel > sizeof(adc_channel2reg)/sizeof(*adc_channel2reg))
255                 return -1;
256
257         mfst->ADC_enabled = (1 << channel);
258
259         mfst->ADC_enabled &= 0xFF;
260         mf624_write16(mfst->ADC_enabled, MFST2REG(mfst, 2, ADCTRL_reg));
261         //print_8bin(ADC_enabled);
262
263         return 0;
264 }
265
266 /* This function blocks until conversion is finished */
267 double ADC_read(mf624_state_t* mfst, adc_channel_t channel)
268 {
269         volatile int i;
270         int result;
271
272         // Activate trigger to start conversion
273         mf624_read16(MFST2REG(mfst, 2, ADSTART_reg));
274
275         // Check if conversion has finished
276         while((mf624_read32(MFST2REG(mfst, 0, GPIOC_reg)) & GPIOC_EOLC_mask)) { 
277                 for (i = 0; i < 1000; i++) {} // small wait
278         }
279
280         ADC_enable(mfst, channel);
281         result = mf624_read16(MFST2REG(mfst, 2, ADDATA0_reg));
282
283         return 10.0 * ((int16_t) (result << 2)) / (double) 0x8000;
284 }
285
286
287 int open_device(char* path) {
288         int device_fd;
289
290         device_fd = open(path, O_RDWR | O_SYNC);
291         if (device_fd == -1) {
292                 perror("open()");
293                 return -1;
294         }
295
296         return device_fd;
297 }
298
299 void wait_for_interrupts(int device_fd)
300 {
301         read(device_fd, NULL, 1);
302 }
303
304 int disable_interrupts(int device_fd)
305 {
306         uint32_t control_value = 0;
307         int status;
308
309         status = write(device_fd, &control_value, sizeof(uint32_t));
310         if (status == -1) {
311                 perror("write()");
312                 return -1;
313         }
314
315         return status;
316 }
317
318 int enable_interrupts(int device_fd)
319 {
320         uint32_t control_value = 1;
321         int status;
322
323         status = write(device_fd, &control_value, sizeof(uint32_t));
324         if (status == -1) {
325                 perror("write()");
326                 return -1;
327         }
328
329         return status;
330 }
331
332 void list_available_mem_regions(char* device)
333 {
334         int status;
335         char path[] = "/sys/class/uio/";
336         char subdir[] = "/maps/";
337         char directory[BUFF_MID];
338         memset(directory, '\0', BUFF_MID);
339
340         DIR *dip;
341         struct dirent *dit;
342
343         strncat(directory, path, strlen(path));
344         strncat(directory, device, min(strlen(device), 8));
345         strncat(directory, subdir, strlen(subdir));
346
347         dip = opendir(directory);
348         if (dip == NULL) {
349                 perror("opendir");
350                 return;
351         }
352
353         while ((dit = readdir(dip)) != NULL) {
354                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
355                         printf(" %s\n", dit->d_name);
356                 }
357         }
358
359         status = closedir(dip);
360         if (status == -1) {
361                 perror("closedir()");
362                 return;
363         }
364
365 }
366
367
368 void list_available_io_ports(char *device)
369 {
370         int status;
371         char path[] = "/sys/class/uio/";
372         char subdir[] = "/portio/";
373         char directory[BUFF_MID];
374         memset(directory, '\0', BUFF_MID);
375
376         DIR *dip;
377         struct dirent *dit;
378
379         strncat(directory, path, strlen(path));
380         strncat(directory, device, min(strlen(device), 8));
381         strncat(directory, subdir, strlen(subdir));
382
383         status = access(directory, F_OK);
384         if (status == -1) {
385                 printf(" There are no IO port available\n");
386                 return;
387         }
388
389         dip = opendir(directory);
390         if (dip == NULL) {
391                 perror("opendir");
392                 return;
393         }
394
395         while ((dit = readdir(dip)) != NULL) {
396                 if (strcmp(dit->d_name, ".") && strcmp(dit->d_name, "..")) {
397                         printf(" %s\n", dit->d_name);
398                 }
399         }
400
401         status = closedir(dip);
402         if (status == -1) {
403                 perror("closedir()");
404                 return;
405         }
406
407 }
408
409
410 void run_simple_tests(char* dev_name)
411 {
412         int status;
413         int device_fd;
414         char buff[BUFF_SMALL];
415         memset(buff, '\0', BUFF_SMALL);
416
417         strncat(buff, "/dev/", 5);
418         strncat(buff, dev_name, min(strlen(dev_name), 8));
419
420         printf("Opening %s\n", buff);
421
422         device_fd = open_device(buff);
423         if (device_fd != -1) {
424                 printf("Tring to enable interrupts\n");
425                 status = enable_interrupts(device_fd);
426                 if (status != -1) {
427                         printf(" Probably OK\n");
428                 }
429         
430                 printf("Tring to disable interrupts\n");
431                 status = disable_interrupts(device_fd);
432                 if (status != -1) {
433                         printf(" Probably OK\n");
434                 }
435         }
436
437
438         printf("Checking for available memory regions exported by the UIO driver\n");
439         list_available_mem_regions(dev_name);
440
441         printf("Checking for available IO ports exported by the UIO driver\n");
442         list_available_io_ports(dev_name);
443 }
444
445 int mmap_regions(mf624_state_t* mfst)
446 {
447         if (bar_mapping_fill(&mfst->bar0, mfst->uio_dev, 0) < 0) {
448                 fprintf(stderr, "%s bar0 mapping fill failed\n", mfst->uio_dev);
449                 return -1;
450         }
451
452         if (bar_mapping_fill(&mfst->bar2, mfst->uio_dev, 1) < 0) {
453                 fprintf(stderr, "%s bar2 mapping fill failed\n", mfst->uio_dev);
454                 return -1;
455         }
456
457         if (bar_mapping_fill(&mfst->bar4, mfst->uio_dev, 2) < 0) {
458                 fprintf(stderr, "%s bar4 mapping fill failed\n", mfst->uio_dev);
459                 return -1;
460         }
461
462         if (bar_mapping_setup(&mfst->bar0, mfst->device_fd) < 0) {
463                 fprintf(stderr, "%s bar0 mapping setup failed\n", mfst->uio_dev);
464                 return -1;
465         }
466
467         if (bar_mapping_setup(&mfst->bar2, mfst->device_fd) < 0) {
468                 fprintf(stderr, "%s bar2 mapping setup failed\n", mfst->uio_dev);
469                 return -1;
470         }
471
472         if (bar_mapping_setup(&mfst->bar4, mfst->device_fd) < 0) {
473                 fprintf(stderr, "%s bar4 mapping setup failed\n", mfst->uio_dev);
474                 return -1;
475         }
476
477 #if 1
478         printf("bar0.phys_addr = %"PRIxPTR"\n", mfst->bar0.phys_addr);
479         printf("bar2.phys_addr = %"PRIxPTR"\n", mfst->bar2.phys_addr);
480         printf("bar4.phys_addr = %"PRIxPTR"\n", mfst->bar4.phys_addr);
481
482         printf("bar0.virt_addr = %"PRIxPTR"\n", mfst->bar0.virt_addr);
483         printf("bar2.virt_addr = %"PRIxPTR"\n", mfst->bar2.virt_addr);
484         printf("bar4.virt_addr = %"PRIxPTR"\n", mfst->bar4.virt_addr);
485 #endif
486
487         return 0;
488 }
489
490
491 int main(int argc, char* argv[])
492 {
493         mf624_state_t* mfst = &mf624_state;
494         char buff[BUFF_SMALL];
495         memset(buff, '\0', BUFF_SMALL);
496
497         if (argc < 2) {
498                 printf("Usage: %s UIO_DEVICE\n   UIO_DEVICE\tname of uio device in /dev\n", argv[0]);
499                 return 1;
500         }
501
502         mfst->uio_dev = argv[1];
503
504         strncat(buff, "/dev/", 5);
505         strncat(buff, mfst->uio_dev, sizeof(buff) - 6);
506
507         mfst->device_fd = open_device(buff);
508         if (mfst->device_fd < 0) {
509                 fprintf(stderr, "%s open failed (%s)!\n", mfst->uio_dev, strerror(errno));
510                 return 2;
511         }
512         if (mmap_regions(mfst) < 0) {
513                 fprintf(stderr, "%s mmap_regions failed (%s)!\n", mfst->uio_dev, strerror(errno));
514                 return 2;
515         }
516
517         DAC_enable(mfst);
518
519         while (1){
520                 printf("Reading DIO: ");
521                 print_8bin(DIO_read(mfst));
522                 sleep(1);
523
524                 printf("Setting DA1 to 10 V\n");
525                 DAC_write(mfst, DA1, 0x3FFF);
526                 sleep(1);
527
528                 printf("Reading ADC0: ");
529                 printf("%f V\n", ADC_read(mfst, AD0));
530                 sleep(1);
531
532                 printf("Reading ADC1: ");
533                 printf("%f V\n", ADC_read(mfst, AD1));
534                 sleep(1);
535
536                 printf("Setting DIO to 0xff\n");
537                 DIO_write(mfst, 0xff);
538                 sleep(1);
539
540                 printf("Setting DIO to 0x00\n");
541                 DIO_write(mfst, 0x00);
542                 sleep(1);
543
544                 printf("Setting DA1 to 5 V\n");
545                 DAC_write(mfst, DA1, 0x3000);
546                 sleep(1);
547                 
548                 printf("Reading ADC0: ");
549                 printf("%f V\n", ADC_read(mfst, AD0));
550                 sleep(1);
551
552                 printf("Reading ADC1: ");
553                 printf("%f V\n", ADC_read(mfst, AD1));
554                 sleep(1);
555                 printf("----------------------\n\n");
556         }
557
558
559         return 0;
560 }