vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / mttn / lib / libmtt.c
blob95aad59878b29c00ff645bffa448e4b6ad36c0a1
1 /**************************************************************************/
2 /* MTT Library routines to support FESA class */
3 /* Fri 20th October 2006 */
4 /* Julian Lewis AB/CO/HT */
5 /**************************************************************************/
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <errno.h> /* Error numbers */
16 #include <sys/file.h>
17 #include <a.out.h>
18 #include <ctype.h>
19 #include <mqueue.h>
20 #include <time.h>
21 #include <math.h>
22 #include <stdint.h>
24 #include <mttdrvr.h>
25 #include <libmtt.h>
27 /* ================================================================ */
28 /* Globals */
30 #define LN 128
31 #define MS100 100000
33 static int mtt = 0; /* File handle on the module */
34 static char objdir[LN]; /* Object directory */
35 static MttDrvrInt connected = 0; /* Connected interrupts */
36 static int noqueueflag = 0; /* Queueing ON */
37 static int timeout = 200; /* 2 Seconds */
38 static int first_task = 1; /* First task number TCB */
39 static int last_task = MttLibTASKS; /* Last task number */
40 static int max_size = MttLibTASK_SIZE; /* Max task size allowed */
42 static char *errstrings[MttLibERRORS] = {
44 /* MttLibErrorNONE, */"No error, all OK",
45 /* MttLibErrorINIT, */"The MTT library has not been initialized",
46 /* MttLibErrorOPEN, */"Unable to open the MTT driver",
47 /* MttLibErrorIO, */"IO error, see errno",
48 /* MttLibErrorSYS, */"Operating system error, see errno",
49 /* MttLibErrorPATH, */"Bad path name syntax",
50 /* MttLibErrorFILE, */"Could not find file, see errno",
51 /* MttLibErrorREAD, */"Can not read file, or file empty",
52 /* MttLibErrorNOMEM, */"Not enough memory",
53 /* MttLibErrorNORELO, */"Task object binary is not relocatable",
54 /* MttLibErrorTOOBIG, */"Task size is too big",
55 /* MttLibErrorEMPTY, */"Object file is empty",
56 /* MttLibErrorFULL, */"No more tasks can be loaded, full up",
57 /* MttLibErrorNOLOAD, */"No such task is loaded",
58 /* MttLibErrorISLOAD, */"Task is already loaded",
59 /* MttLibErrorNAME, */"Illegal task name",
60 /* MttLibErrorLREG, */"No such local register",
61 /* MttLibErrorGREG, */"No such global register"
65 /* =========================== */
66 /* Open MTT driver file handel */
67 static int MttOpen() {
69 char fnm[32];
70 int i, fn;
72 for (i = 1; i <= SkelDrvrCLIENT_CONTEXTS; i++) {
73 sprintf(fnm, "/dev/%s.%1d", "mtt", i);
74 if ((fn = open(fnm, O_RDWR, 0)) > 0)
75 return (fn);
77 return (0);
80 /* =========================== */
82 void MttLibUsleep(int dly) {
83 struct timespec rqtp, rmtp; /* 'nanosleep' time structure */
84 rqtp.tv_sec = 0;
85 rqtp.tv_nsec = dly * 1000;
86 nanosleep(&rqtp, &rmtp);
89 /* ============================= */
90 /* Get a file configuration path */
92 #if 0
93 #ifdef __linux__
94 static char *defaultconfigpath = "/dsrc/drivers/mtt/test/mttconfig.linux";
95 #else
96 static char *defaultconfigpath = "/dsc/data/mtt/Mtt.conf";
97 #endif
99 static char *configpath = NULL;
101 char *MttLibGetFile(char *name) {
102 FILE *gpath = NULL;
103 char txt[LN];
104 int i, j;
106 static char path[LN];
108 if (configpath) {
109 gpath = fopen(configpath,"r");
110 if (gpath == NULL) {
111 configpath = NULL;
115 if (configpath == NULL) {
116 configpath = defaultconfigpath;
117 gpath = fopen(configpath,"r");
118 if (gpath == NULL) {
119 configpath = NULL;
120 sprintf(path,"./%s",name);
121 return path;
125 bzero((void *) path,LN);
127 while (1) {
128 if (fgets(txt,LN,gpath) == NULL) break;
129 if (strncmp(name,txt,strlen(name)) == 0) {
130 for (i=strlen(name); i<strlen(txt); i++) {
131 if (txt[i] != ' ') break;
133 j= 0;
134 while ((txt[i] != ' ') && (txt[i] != 0) && (txt[i] != '\n')) {
135 path[j] = txt[i];
136 j++; i++;
138 strcat(path,name);
139 fclose(gpath);
140 return path;
143 fclose(gpath);
144 return NULL;
146 #endif
148 /* ================================== */
149 /* Read object code binary from file */
151 MttLibError MttLibReadObject(FILE *objFile, ProgramBuf *code) {
153 Instruction *inst;
154 int i;
155 char ln[LN], *cp, *ep;
157 if (fgets(ln, LN, objFile)) {
158 cp = ln;
159 code->LoadAddress = strtoul(cp, &ep, 0);
160 cp = ep;
161 code->InstructionCount = strtoul(cp, &ep, 0);
162 } else
163 return MttLibErrorREAD;
165 inst = (Instruction *) malloc(sizeof(Instruction) * code->InstructionCount);
166 if (inst == NULL)
167 return MttLibErrorNOMEM;
169 code->Program = inst;
171 for (i = 0; i < code->InstructionCount; i++) {
172 inst = &(code->Program[i]);
173 bzero((void *) ln, LN);
174 if (fgets(ln, LN, objFile)) {
175 cp = ln;
176 inst->Number = (unsigned short) strtoul(cp, &ep, 0);
177 cp = ep;
178 inst->Src1 = strtoul(cp, &ep, 0);
179 cp = ep;
180 inst->Src2 = (unsigned short) strtoul(cp, &ep, 0);
181 cp = ep;
182 inst->Dest = (unsigned short) strtoul(cp, &ep, 0);
183 cp = ep;
184 inst->Crc = (unsigned short) strtoul(cp, &ep, 0);
187 return MttLibErrorNONE;
190 /* =================================== */
191 /* String to upper case until a space */
193 static void StrToUpper(inp, out)
194 char *inp;char *out; {
196 int i;
197 char *cp;
199 for (i = 0; i < strlen(inp); i++) {
200 cp = &(inp[i]);
201 if (*cp == ' ')
202 break;
203 if ((*cp >= 'a') && (*cp <= 'z'))
204 *cp -= ' ';
205 out[i] = *cp;
207 out[i] = 0;
210 /* ============================== */
211 /* String to Register */
213 unsigned long MttLibStringToReg(char *name, MttLibRegType *lorg) {
215 int i;
216 unsigned long rn, en, st, of, lg, rs;
217 char upr[MAX_REGISTER_STRING_LENGTH + 1], *cp, *ep;
219 cp = name;
220 if (cp) {
221 StrToUpper(cp, upr);
222 if (strlen(upr) <= MAX_REGISTER_STRING_LENGTH) {
223 for (i = 0; i < REGNAMES; i++) {
224 if (strncmp(upr, Regs[i].Name, strlen(Regs[i].Name)) == 0) {
226 st = Regs[i].Start;
227 en = Regs[i].End;
228 of = Regs[i].Offset;
229 lg = Regs[i].LorG;
231 if (st < en) {
232 if (strlen(Regs[i].Name) < strlen(name)) {
233 cp = name + strlen(Regs[i].Name);
234 rn = strtoul(cp, &ep, 0);
235 if (cp != ep) {
236 if ((rn >= of) && (rn <= en - st + of)) {
237 *lorg = lg;
238 rs = st + rn - of;
239 if (lg == LOCAL_REG)
240 rs -= GLOBALS;
241 return rs;
245 } else
246 return st;
251 return 0;
254 /* ============================== */
255 /* Register To String */
257 char *MttLibRegToString(int regnum, MttLibRegType lorg) {
259 static char name[MAX_REGISTER_STRING_LENGTH];
260 int rn, i;
261 RegisterDsc *reg;
263 if (lorg == MttLibRegTypeLOCAL)
264 regnum += GLOBALS;
266 for (i = 0; i < REGNAMES; i++) {
267 reg = &(Regs[i]);
268 if ((regnum >= reg->Start) && (regnum <= reg->End)) {
269 rn = (regnum - reg->Start) + reg->Offset;
270 if (reg->Start < reg->End)
271 sprintf(name, "%s%1d", reg->Name, rn);
272 else
273 sprintf(name, "%s", reg->Name);
274 return name;
277 return "???";
280 /* ================================================================ */
281 /* Initialize the MTT library. This routine opens the driver, and */
282 /* initializes the MTT module. The supplied path is where the */
283 /* library will look to find the compiled event table object files. */
284 /* Notice we don't pass event tables through reflective memory. */
285 /* The path name must end with the character '/' and be less than */
286 /* LN (128) characters long. If Path is NULL the default is path is */
287 /* used as defined in libmtt.h DEFAULT_OBJECT_PATH */
289 int sysldr = 0;
291 MttLibError MttLibInit(char *path) {
293 uint32_t enb, stat, autc, msk;
294 time_t tim;
295 MttDrvrTime t;
297 if (path == NULL)
298 strncpy(objdir, MttLibDEFAULT_OBJECT_PATH, LN);
299 else {
300 if (strlen(path) >= 1) {
301 strncpy(objdir, path, LN);
302 if ( path[strlen(objdir) - 1] != '/')
303 strcat(objdir,"/");
304 } else
305 return MttLibErrorPATH;
307 if (mtt != 0) {
308 close(mtt);
309 mtt = 0;
312 mtt = MttOpen();
313 if (mtt == 0)
314 return MttLibErrorOPEN;
316 if (ioctl(mtt, MTT_IOCGSTATUS, &stat) < 0) {
317 mtt = 0;
318 return MttLibErrorIO;
321 if ((sysldr) || ((stat & MttDrvrStatusENABLED) == 0)) {
322 enb = 1;
323 if (ioctl(mtt, MTT_IOCSOUT_ENABLE, &enb) < 0) {
324 close(mtt);
325 mtt = 0;
326 return MttLibErrorIO;
330 if ((sysldr) || ((stat & MttDrvrStatusUTC_SET) == 0)) {
331 msk = MttLibWait(MttDrvrIntPPS, 0, 200);
332 if (msk & MttDrvrIntPPS) {
333 MttLibUsleep(MS100);
334 if (time(&tim) > 0) {
335 t.Second = tim + 1;
336 t.MilliSecond = 0;
337 if (ioctl(mtt, MTT_IOCSUTC, &t.Second) < 0) {
338 close(mtt);
339 mtt = 0;
340 return MttLibErrorIO;
342 } else {
343 close(mtt);
344 mtt = 0;
345 return MttLibErrorSYS;
347 } else {
348 close(mtt);
349 mtt = 0;
350 return MttLibErrorIO;
354 if ((sysldr) || ((stat & MttDrvrStatusUTC_SENDING_ON) == 0)) {
355 autc = 1;
356 if (ioctl(mtt, MTT_IOCSUTC_SENDING, &autc) < 0) {
357 close(mtt);
358 mtt = 0;
359 return MttLibErrorIO;
362 return MttLibErrorNONE;
365 /* ================================================================ */
366 /* Get a string for an MttLibError code */
368 char *MttLibErrorToString(MttLibError err) {
370 if (err >= MttLibERRORS)
371 return "No such error code";
372 return errstrings[err];
375 /* ================================================================ */
376 /* Read task program object from MTT program memory */
377 /* The pointers *instructions must be 'free' after the call. */
379 MttLibError
380 MttLibReadTaskObject(char *name, ProgramBuf *pbf, Instruction **instructions)
382 MttDrvrTaskBlock *tcbp;
383 MttDrvrTaskBuf tbuf;
384 int i;
386 /* sanity checks */
387 if (mtt == 0)
388 return MttLibErrorINIT;
389 if (name == NULL || !strlen(name) ||
390 strlen(name) >= MttLibMAX_NAME_SIZE ||
391 strlen(name) < MttLibMIN_NAME_SIZE ||
392 !strcmp(name, "ALL") || !isalpha((int)name[0])) {
393 return MttLibErrorNAME;
395 for (i = 1; i < strlen(name); i++) {
396 if (name[i] != '_' && name[i] != '.' && !isalnum((int)name[i]))
397 return MttLibErrorNAME;
400 /* fill in task buffer */
401 tcbp = &tbuf.ControlBlock;
402 for (i = first_task - 1; i < last_task; i++) {
403 tbuf.Task = i + 1;
404 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
405 return MttLibErrorIO;
406 if (strncmp(tbuf.Name, name, MttLibMAX_NAME_SIZE) == 0)
407 break;
409 if (i >= last_task)
410 return MttLibErrorNOLOAD;
412 if (tbuf.InstructionCount == 0)
413 return MttLibErrorEMPTY;
415 /* fetch the program from hardware */
416 pbf->InstructionCount = tbuf.InstructionCount;
417 pbf->LoadAddress = tbuf.LoadAddress;
419 *instructions = malloc(tbuf.InstructionCount * sizeof(Instruction));
420 if (*instructions == NULL)
421 return MttLibErrorNOMEM;
422 pbf->Program = *instructions;
424 if (ioctl(mtt, MTT_IOCGPROGRAM, pbf) < 0) {
425 free(*instructions);
426 return MttLibErrorIO;
428 return MttLibErrorNONE;
431 /* ================================================================ */
432 /* Load task program object into MTT program memory */
434 MttLibError MttLibLoadTaskObject(char *name, ProgramBuf *pbf) {
436 int i;
437 MttDrvrTaskBuf tbuf;
438 MttDrvrTaskBlock *tcbp;
439 unsigned long tn, ftn, tcnt, tval;
440 uint32_t tmsk;
442 if (mtt == 0)
443 return MttLibErrorINIT;
445 if ((name == NULL) || (strlen(name) == 0) || (strlen(name)
446 >= MttLibMAX_NAME_SIZE) || (strcmp(name, "ALL") == 0) || (isalpha(
447 (int) name[0]) == 0))
448 return MttLibErrorNAME;
450 for (i = 1; i < strlen(name); i++) {
451 if ((name[i] != '_') && (name[i] != '.') && (isalnum((int) name[i])
452 == 0))
453 return MttLibErrorNAME;
455 if (strlen(name) < MttLibMIN_NAME_SIZE)
456 return MttLibErrorNAME;
458 if (pbf->LoadAddress != 0)
459 return MttLibErrorNORELO;
460 if (pbf->InstructionCount == 0)
461 return MttLibErrorEMPTY;
463 tcnt = (pbf->InstructionCount / (max_size + 1)) + 1;
464 tval = 0;
466 tcbp = &(tbuf.ControlBlock);
467 for (i = first_task - 1; i < last_task; i++) {
468 tn = i + 1;
469 tbuf.Task = tn;
470 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
471 return MttLibErrorIO;
472 if (strncmp(tbuf.Name, name, MttLibMAX_NAME_SIZE) == 0)
473 return MttLibErrorISLOAD;
475 for (i = first_task - 1; i < last_task; i++) {
476 tn = i + 1;
477 tbuf.Task = tn;
478 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
479 return MttLibErrorIO;
480 if (strlen(tbuf.Name) == 0) {
481 tmsk = 1 << i;
482 ioctl(mtt, MTT_IOCSTASKS_STOP, &tmsk);
483 if (tval == 0)
484 ftn = tn;
485 tval++;
486 if (tval >= tcnt)
487 break;
488 } else
489 tval = 0;
491 if (tval == 0)
492 return MttLibErrorNOMEM;
494 pbf->LoadAddress = max_size * (tn - 1);
495 if (ioctl(mtt, MTT_IOCSPROGRAM, pbf) < 0)
496 return MttLibErrorIO;
498 for (i = ftn; i < ftn + tval; i++) {
499 tbuf.Task = i;
500 tbuf.Fields = MttDrvrTBFAll;
501 tbuf.LoadAddress = pbf->LoadAddress;
502 tbuf.InstructionCount = pbf->InstructionCount;
503 tbuf.PcStart = 0;
504 tcbp->Pc = tbuf.PcStart;
505 tcbp->PcOffset = tbuf.LoadAddress;
507 strncpy(tbuf.Name, name, MttLibMAX_NAME_SIZE);
508 if (ioctl(mtt, MTT_IOCSTCB, &tbuf) < 0)
509 return MttLibErrorIO;
511 return MttLibErrorNONE;
514 /* ================================================================ */
515 /* Load/UnLoad a compiled table object from the path specified in */
516 /* the initialization routine into a spare task slot if one exists. */
517 /* Memory handling may result in running tasks being moved around. */
518 /* Task names must be alpha numeric strings with the first char a */
519 /* letter and less than MttLibMAX_NAME_SIZE characters. */
520 /* The special name "ALL" can be used in calls to the UnLoad */
521 /* function to force all tasks and any zombies to be unloaded. */
523 MttLibError MttLibLoadTask(char *name) {
525 int i;
526 char fname[LN];
527 FILE *fhand;
528 ProgramBuf pbf;
529 MttLibError err;
531 if (mtt == 0)
532 return MttLibErrorINIT;
534 if ((name == NULL) || (strlen(name) == 0) || (strlen(name)
535 >= MttLibMAX_NAME_SIZE) || (strcmp(name, "ALL") == 0) || (isalpha(
536 (int) name[0]) == 0))
537 return MttLibErrorNAME;
538 for (i = 1; i < strlen(name); i++) {
539 if ((name[i] != '_') && (name[i] != '.') && (isalnum((int) name[i])
540 == 0))
541 return MttLibErrorNAME;
543 if (strlen(name) < MttLibMIN_NAME_SIZE)
544 return MttLibErrorNAME;
546 sprintf(fname, "%s%s", objdir, name);
547 fhand = fopen(fname, "r");
548 if (fhand == NULL)
549 return MttLibErrorFILE;
550 err = MttLibReadObject(fhand, &pbf);
551 fclose(fhand);
552 if (err)
553 return err;
555 err = MttLibLoadTaskObject(name, &pbf);
556 free(pbf.Program);
557 return err;
560 /* ================================================================ */
562 MttLibError MttLibUnloadTask(char *name) {
564 int i, all, err;
565 MttDrvrTaskBuf tbuf;
566 MttDrvrTaskBlock *tcbp;
567 unsigned long tn;
568 uint32_t tmsk;
570 if (mtt == 0)
571 return MttLibErrorINIT;
573 if (strcmp(name, "ALL") == 0)
574 all = 1;
575 else
576 all = 0;
578 err = 0;
580 tcbp = &(tbuf.ControlBlock);
581 for (i = first_task - 1; i < last_task; i++) {
582 tn = i + 1;
583 tbuf.Task = tn;
584 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
585 return MttLibErrorIO;
586 if ((all) || (strcmp(name, tbuf.Name) == 0)) {
587 tmsk = 1 << i;
588 err += ioctl(mtt, MTT_IOCSTASKS_STOP, &tmsk);
589 bzero((void *) tbuf.Name, MttLibMAX_NAME_SIZE);
590 err += ioctl(mtt, MTT_IOCSTCB, &tbuf);
593 if ((err < 0) && (all == 0))
594 return MttLibErrorNOLOAD;
595 return MttLibErrorNONE;
598 /* ================================================================ */
599 /* Unload all tasks */
601 MttLibError MttLibUnloadTasks(void)
603 return MttLibUnloadTask("ALL");
606 /* ================================================================ */
607 /* Here the names pointer should be able to store MttLibTABLES char */
608 /* pointers. Loaded tasks reside in MTT memory, and are running if */
609 /* they are not stopped. Do not confuse this state with the run and */
610 /* wait bit masks in the event table task logic. */
612 MttLibError MttLibGetLoadedTasks(MttLibName *names) {
614 int i;
615 MttDrvrTaskBuf tbuf;
616 MttDrvrTaskBlock *tcbp;
617 unsigned long tn;
619 if (mtt == 0)
620 return MttLibErrorINIT;
622 tcbp = &(tbuf.ControlBlock);
623 for (i = first_task - 1; i < last_task; i++) {
624 tn = i + 1;
625 tbuf.Task = tn;
626 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
627 return MttLibErrorIO;
628 if (strlen(tbuf.Name))
629 strncpy(names[i], tbuf.Name, MttLibMAX_NAME_SIZE);
630 else
631 names[i][0] = 0;
633 return MttLibErrorNONE;
636 /* ================================================================ */
638 MttLibError MttLibGetRunningTasks(MttLibName *names) {
640 int i;
641 MttDrvrTaskBuf tbuf;
642 MttDrvrTaskBlock *tcbp;
643 unsigned long tn;
645 if (mtt == 0)
646 return MttLibErrorINIT;
648 tcbp = &(tbuf.ControlBlock);
649 for (i = first_task - 1; i < last_task; i++) {
650 tn = i + 1;
651 tbuf.Task = tn;
652 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
653 return MttLibErrorIO;
654 if (strlen(tbuf.Name) && tcbp->TaskStatus & MttDrvrTaskStatusRUNNING)
655 strncpy(names[i], tbuf.Name, MttLibMAX_NAME_SIZE);
656 else
657 names[i][0] = '\0';
659 return MttLibErrorNONE;
662 /* ================================================================ */
663 /* Each task running an event table has MttLibLocakREGISTERS that */
664 /* can be used to contain task parameters such as the run count. */
665 /* The caller must know what these parameters mean for event tasks. */
667 MttLibError MttLibSetTaskRegister(char *name, MttLibLocalRegister treg,
668 unsigned long val) {
670 int i;
671 MttDrvrTaskBuf tbuf;
672 MttDrvrTaskBlock *tcbp;
673 unsigned long tn;
674 MttDrvrTaskRegBuf lrb;
676 if (mtt == 0)
677 return MttLibErrorINIT;
679 if (treg >= MttLibLocalREGISTERS)
680 return MttLibErrorLREG;
682 tcbp = &(tbuf.ControlBlock);
683 for (i = first_task - 1; i < last_task; i++) {
684 tn = i + 1;
685 tbuf.Task = tn;
686 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
687 return MttLibErrorIO;
688 if (strcmp(name, tbuf.Name) == 0) {
689 lrb.Task = tn;
690 lrb.RegMask = 1 << treg;
691 lrb.RegVals[treg] = val;
692 if (ioctl(mtt, MTT_IOCSTRVAL, &lrb) < 0)
693 return MttLibErrorIO;
694 return MttLibErrorNONE;
697 return MttLibErrorNOLOAD;
700 /* ================================================================ */
702 MttLibError MttLibGetTaskRegister(char *name, MttLibLocalRegister treg,
703 unsigned long *val) {
704 int i;
705 MttDrvrTaskBuf tbuf;
706 MttDrvrTaskBlock *tcbp;
707 unsigned long tn;
708 MttDrvrTaskRegBuf lrb;
710 if (mtt == 0)
711 return MttLibErrorINIT;
713 if (treg >= MttLibLocalREGISTERS)
714 return MttLibErrorLREG;
716 tcbp = &(tbuf.ControlBlock);
717 for (i = first_task - 1; i < last_task; i++) {
718 tn = i + 1;
719 tbuf.Task = tn;
720 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
721 return MttLibErrorIO;
722 if (strcmp(name, tbuf.Name) == 0) {
723 lrb.Task = tn;
724 lrb.RegMask = 1 << treg;
725 if (ioctl(mtt, MTT_IOCGTRVAL, &lrb) < 0)
726 return MttLibErrorIO;
727 *val = lrb.RegVals[treg];
728 return MttLibErrorNONE;
731 return MttLibErrorNOLOAD;
734 /* ================================================================ */
736 MttLibError MttLibGetTaskRegisters(char *name, MttLibTaskRegisters *phLRegs) {
737 int i;
738 MttDrvrTaskBuf tbuf;
739 MttDrvrTaskBlock *tcbp;
740 unsigned long tn;
741 MttDrvrTaskRegBuf lreg;
743 if (mtt == 0)
744 return MttLibErrorINIT;
746 tcbp = &(tbuf.ControlBlock);
747 for (i = first_task - 1; i < last_task; i++) {
748 tn = i + 1;
749 tbuf.Task = tn;
750 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
751 return MttLibErrorIO;
752 if (strcmp(name, tbuf.Name) == 0) {
753 int j;
754 lreg.Task = tn;
755 lreg.RegMask = -1;
756 if (ioctl(mtt, MTT_IOCGTRVAL, &lreg) < 0)
757 return MttLibErrorIO;
758 for (j=0;j<MttDrvrLRAM_SIZE;j++ )
759 phLRegs->RegVals[j]=lreg.RegVals[j];
760 phLRegs->Task=lreg.Task;
761 phLRegs->RegMask=lreg.RegMask;
762 return MttLibErrorNONE;
765 return MttLibErrorNOLOAD;
768 /* ================================================================ */
769 /* Tasks running event tables can be started, stopped or continued. */
770 /* Starting a task loads its program counter with its start address */
771 /* Stopping a task stops it dead, Continuing a task continues from */
772 /* the last program counter value without reloading it. */
774 MttLibError MttLibStartTask(char *name) {
776 int i;
777 MttDrvrTaskBuf tbuf;
778 MttDrvrTaskBlock *tcbp;
779 unsigned long tn;
780 uint32_t tmsk;
782 if (mtt == 0)
783 return MttLibErrorINIT;
785 tcbp = &(tbuf.ControlBlock);
786 for (i = first_task - 1; i < last_task; i++) {
787 tn = i + 1;
788 tbuf.Task = tn;
789 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
790 return MttLibErrorIO;
791 if (strcmp(name, tbuf.Name) == 0) {
792 tmsk = 1 << i;
793 if (ioctl(mtt, MTT_IOCSTASKS_START, &tmsk) < 0)
794 return MttLibErrorIO;
795 return MttLibErrorNONE;
798 return MttLibErrorNOLOAD;
801 /* ================================================================ */
803 MttLibError MttLibStopTask(char *name) {
805 int i;
806 MttDrvrTaskBuf tbuf;
807 MttDrvrTaskBlock *tcbp;
808 unsigned long tn;
809 uint32_t tmsk;
811 if (mtt == 0)
812 return MttLibErrorINIT;
814 tcbp = &(tbuf.ControlBlock);
815 for (i = first_task - 1; i < last_task; i++) {
816 tn = i + 1;
817 tbuf.Task = tn;
818 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
819 return MttLibErrorIO;
820 if (strcmp(name, tbuf.Name) == 0) {
821 tmsk = 1 << i;
822 if (ioctl(mtt, MTT_IOCSTASKS_STOP, &tmsk) < 0)
823 return MttLibErrorIO;
824 return MttLibErrorNONE;
827 return MttLibErrorNOLOAD;
830 /* ================================================================ */
832 MttLibError MttLibContinueTask(char *name) {
834 int i;
835 MttDrvrTaskBuf tbuf;
836 MttDrvrTaskBlock *tcbp;
837 unsigned long tn;
838 uint32_t tmsk;
840 if (mtt == 0)
841 return MttLibErrorINIT;
843 tcbp = &(tbuf.ControlBlock);
844 for (i = first_task - 1; i < last_task; i++) {
845 tn = i + 1;
846 tbuf.Task = tn;
847 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
848 return MttLibErrorIO;
849 if (strcmp(name, tbuf.Name) == 0) {
850 tmsk = 1 << i;
851 if (ioctl(mtt, MTT_IOCSTASKS_CONT, &tmsk) < 0)
852 return MttLibErrorIO;
853 return MttLibErrorNONE;
856 return MttLibErrorNOLOAD;
859 /* ================================================================ */
860 /* The task status enumeration is defined in the driver includes. */
861 /* By including mttdrvr.h then mtthard.h is also included, and in */
862 /* this hardware description file MtttDrvrTaskStatus is defined. */
863 /* The task status has values like Running, Stopped, Waiting etc */
865 uint32_t MttLibGetTaskStatus(char *name) {
867 int i;
868 MttDrvrTaskBuf tbuf;
869 MttDrvrTaskBlock *tcbp;
870 unsigned long tn;
872 if (mtt == 0)
873 return 0;
875 tcbp = &(tbuf.ControlBlock);
876 for (i = first_task - 1; i < last_task; i++) {
877 tn = i + 1;
878 tbuf.Task = tn;
879 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
880 return MttLibErrorIO;
881 if (strcmp(name, tbuf.Name) == 0)
882 return tcbp->TaskStatus;
884 return 0;
887 static MttLibError __send_event(int frame, int priority)
889 MttDrvrEvent event;
891 if (mtt == 0)
892 return MttLibErrorINIT;
894 event.Frame = frame;
895 event.Priority = priority;
896 if (ioctl(mtt, MTT_IOCSSEND_EVENT, &event) < 0)
897 return MttLibErrorIO;
899 return MttLibErrorNONE;
902 /* ================================================================ */
903 /* Calling this routine sends out the specified frame immediately. */
904 /* The event will be sent in the high priority queue */
906 MttLibError MttLibSendEvent(unsigned long frame) {
908 return __send_event(frame, 0);
911 MttLibError MttLibSendEventPrio(unsigned long frame, int priority)
913 return __send_event(frame, priority);
916 /* ================================================================ */
917 /* This routine allows you to connect to MTT interrupts and wait */
918 /* for them to arrive. You supply a mask defined in mtthard.h that */
919 /* defines which interrupts you want to wait for. The possible */
920 /* interrupts are error conditions, task interrupts, the PPS, SYNC, */
921 /* and software triggered events. The noqueue flag kills the queue */
922 /* if it has a non zero value. Tmo is the timeout in 10ms units. */
923 /* A tmo value of zero means no timeout, hence wait indefinatley. */
925 uint32_t MttLibWait(uint32_t mask, int noqueue, int tmo) {
927 SkelDrvrConnection con;
928 SkelDrvrReadBuf rbf;
929 int cc;
931 if (mtt == 0)
932 return 0;
934 if ((mask & connected) != mask) {
935 con.Module = 1;
936 con.ConMask = mask;
937 if (ioctl(mtt, SkelDrvrIoctlCONNECT, &con) < 0)
938 return 0;
939 connected |= mask;
941 if (noqueue != noqueueflag) {
942 if (ioctl(mtt, SkelDrvrIoctlSET_QUEUE_FLAG, &noqueue) < 0)
943 return MttLibErrorIO;
944 noqueueflag = noqueue;
947 if (tmo != timeout) {
948 if (ioctl(mtt, SkelDrvrIoctlSET_TIMEOUT, &timeout) < 0)
949 return MttLibErrorIO;
950 timeout = tmo;
953 while (1) {
954 cc = read(mtt, &rbf, sizeof(SkelDrvrReadBuf));
955 if (cc <= 0)
956 return 0;
957 if (mask == 0)
958 return rbf.Connection.ConMask;
959 if (mask & rbf.Connection.ConMask)
960 return rbf.Connection.ConMask;
962 return 0;
965 /* ================================================================ */
966 /* The Mtt module status can be read to check its functioning. */
967 /* MttDrvrStatus is defined in mtthard.h. */
969 uint32_t MttLibGetStatus() {
971 uint32_t stat;
973 if (mtt == 0)
974 return 0;
976 if (ioctl(mtt, MTT_IOCGSTATUS, &stat) < 0)
977 return 0;
978 return (MttDrvrStatus) stat;
981 /* ================================================================ */
982 /* Global Mtt module registers contain stuff like telegrams, UTC */
983 /* and other stuff. The exact meaning of these registers will */
984 /* depend completely on the tasks running in the Mtt module. The */
985 /* caller needs to be aware of the register usage conventions. */
987 MttLibError MttSetGlobalRegister(MttLibGlobalRegister greg, unsigned long val) {
989 MttDrvrGlobalRegBuf grb;
991 if (mtt == 0)
992 return MttLibErrorINIT;
994 if (greg >= MttLibGlobalREGISTERS)
995 return MttLibErrorGREG;
997 grb.RegNum = greg;
998 grb.RegVal = val;
999 if (ioctl(mtt, MTT_IOCSGRVAL, &grb) < 0)
1000 return MttLibErrorIO;
1002 return MttLibErrorNONE;
1005 /* ================================================================ */
1007 MttLibError MttGetGlobalRegister(MttLibGlobalRegister greg, unsigned long *val) {
1009 MttDrvrGlobalRegBuf grb;
1011 if (mtt == 0)
1012 return MttLibErrorINIT;
1014 if (greg >= MttLibGlobalREGISTERS)
1015 return MttLibErrorGREG;
1017 grb.RegNum = greg;
1018 if (ioctl(mtt, MTT_IOCGGRVAL, &grb) < 0)
1019 return MttLibErrorIO;
1020 *val = grb.RegVal;
1022 return MttLibErrorNONE;
1025 /* ================================================================ */
1026 /* This routine returns the mtt driver file handle so that direct */
1027 /* client ioctl calls can be made. */
1029 int MttLibGetHandle() {
1030 return mtt;
1033 /* ================================================================ */
1034 /* Set task range. */
1035 /* Never call this routine unless the task size is too small. */
1037 MttLibError MttLibSetTaskRange(unsigned int first, unsigned int last,
1038 unsigned int isize) {
1040 if ((first < 1) || (first > MttDrvrTASKS) || (last <= first) || (last
1041 > MttDrvrTASKS))
1042 return MttLibErrorNOLOAD;
1044 first_task = first; /* First task number 1..MttDrvrTASKS */
1045 last_task = last; /* Last task number 1..MttDrvrTASKS */
1046 max_size = isize; /* Number of instructions per task */
1048 return MttLibErrorNONE;
1050 /* ================================================================ */
1051 /* Get task range. */
1053 void MttLibGetTaskRange(unsigned int *first, unsigned int *last,
1054 unsigned int *isize) {
1056 *first = first_task;
1057 *last = last_task;
1058 *isize = max_size;
1061 /* ================================================================ */
1062 /* Get the TCB number for a given named task, 1..16. If the task is */
1063 /* not found the routine returns zero. */
1065 int MttLibGetTcbNum(char *name) {
1067 int i;
1068 MttDrvrTaskBuf tbuf;
1069 MttDrvrTaskBlock *tcbp;
1070 unsigned long tn;
1072 if (mtt == 0)
1073 return 0;
1075 tcbp = &(tbuf.ControlBlock);
1076 for (i = first_task - 1; i < last_task; i++) {
1077 tn = i + 1;
1078 tbuf.Task = tn;
1079 if (ioctl(mtt, MTT_IOCGTCB, &tbuf) < 0)
1080 return MttLibErrorIO;
1081 if (strcmp(name, tbuf.Name) == 0)
1082 return tn;
1084 return 0;
1087 #if 0
1088 /* ================================================================ */
1089 /* Get host configuration character */
1091 char MttLibGetConfgChar(int n) {
1093 char *cp, fname[LN], ln[LN];
1094 FILE *fp;
1096 cp = MttLibGetFile("Mtt.hostconfig");
1097 if (cp) {
1098 strcpy(fname, cp);
1099 fp = fopen(fname, "r");
1100 if (fp) {
1101 cp = fgets(ln, LN, fp);
1102 fclose(fp);
1103 if (n < strlen(ln))
1104 return ln[n];
1107 return '?';
1110 /* ================================================================ */
1111 /* Get host configuration ID (M, A or B) */
1113 char MttLibGetHostId() {
1114 return MttLibGetConfgChar(0);
1117 /* ================================================================= */
1118 /* Compile an event table by sending a message to the table compiler */
1119 /* server message queue. The resulting object file is transfered to */
1120 /* the LHC MTGs accross reflective memory. This routine avoids the */
1121 /* need for issuing system calls within complex multithreaded FESA */
1122 /* classes. The table must be loaded as usual and completion must */
1123 /* be checked as usual by looking at the response xmem tables. */
1124 /* If the return code is an IO error this probably means the cmtsrv */
1125 /* task is not running. A SYS error indicates a message queue error. */
1129 /* See libxmem, I had to use xmem to check for update of the object */
1130 /* table. This delays CompileTable until the object is loaded in to */
1131 /* the reflective memory table. */
1132 /* I can't put xmem calls here as others use this library. */
1134 MttLibError MttLibCompileTable(char *name) {
1136 ssize_t ql;
1137 mqd_t q;
1138 int terr;
1140 q = mq_open("/tmp/cmtsrv",(O_WRONLY | O_NONBLOCK));
1141 if (q == (mqd_t) -1) return MttLibErrorIO;
1143 ql = mq_send(q,name,MttLibMAX_NAME_SIZE,NULL);
1144 terr = errno;
1145 mq_close(q);
1146 if (q == (mqd_t) -1) {
1147 if (terr == EAGAIN) return MttLibErrorIO;
1148 else return MttLibErrorSYS;
1150 return MttLibErrorNONE;
1152 #endif