-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrtos1.c
2717 lines (2109 loc) · 105 KB
/
rtos1.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//******************************************************************************//
// INFO //
//******************************************************************************//
// File : 07_RTOS.c //
// Author : Aditya Mall //
// Date : 03/17/2019 //
// Copyright : (c) 2019, Aditya Mall, Mentor: Dr. Jason Losh, //
// The University of Texas at Arlington. //
// Project : RTOS Framework EK-TM4C123GXL Evaluation Board. //
// Target Platform : EK-TM4C123GXL Evaluation Board //
// Target uC : TM4C123GH6PM //
// IDE : Code Composer Studio v7 //
// System Clock : 40 MHz //
// UART Baudrate : 115200 //
// Data Length : 8 Bits //
// Version : 1.7 //
// Version Control : GIT //
// //
// Hardware configuration: //
// //
// (On Board) //
// - Red LED at PF1 drives an NPN transistor that powers the red LED //
// - Blue LED at PF2 drives an NPN transistor that powers the blue LED //
// - Green LED at PF3 drives an NPN transistor that powers the green LED //
// - Pushbutton at SW1 pulls pin PF4 low (internal pull-up is used) //
// - UART Interface: //
// U0TX (PA1) and U0RX (PA0) are connected to the 2nd controller //
// Configured to 115,200 baud, 8N1 //
// //
// (External Modules) //
// - 5 Pushbuttons and 5 LEDs, UART //
// - LEDS on these pins: //
// - Blue: PF2 (on-board) //
// - Red: PE1 //
// - Green: PE2 //
// - Yellow: PE3 //
// - Orange: PE4 //
// - PB0: PA2 //
// - PB1: PA3 //
// - PB2: PA4 //
// - PB3: PA6 //
// - PB4: PA7 //
// //
// //
//******************************************************************************//
// ATTENTION //
//******************************************************************************//
// //
// This Software was made by Aditya Mall, under the guidance of Dr. Jason Losh, //
// The University of Texas at Arlington. Any UNAUTHORIZED use of this software, //
// without the prior permission and consent of Dr. Jason Losh or any of the, //
// mentioned contributors is a direct violation of Copyright. //
// //
// THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED //
// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF //
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. //
// ADITYA MALL OR ANY MENTIONED CONTRIBUTORS SHALL NOT, IN ANY CIRCUMSTANCES, //
// BE LIABLE FOR SPECIAL, INCIDENTAL,OR CONSEQUENTIAL DAMAGES, //
// FOR ANY REASON WHATSOEVER. //
// //
// For more info please contact: [email protected] //
// //
//******************************************************************************//
//***** References and Citations ******//
//
// 1) ANSI VT100 escape sequence sourced from: "http://ascii-table.com/ansi-escape-sequences-vt-100.php"
// 2) VT100 Operating system control sequences sourced from "http://rtfm.etla.org/xterm/ctlseq.html"
// 3) List of Unicode Characters "https://en.wikipedia.org/wiki/List_of_Unicode_characters"
// 4) Moving Average filter from IIR filter implementation given by Dr.Jason Losh from previous EE5314, Fall 2018 Project
//
//*************************************//
//*********** Versions ***************//
//
// Version 1.7 -(03/17/2019)
// info:
// - Documentation and formating changes added
//
// Version 1.7 -(03/16/2019)
// info:
// - CPU task runtime calculations added
// - shell command or creating thread added as <task name> '&'
//
// Version 1.5.5.2 -(03/14/2019)
// info:
// - 'pi' (priority inheritance) functionality added.
// - ps and ipcs table formatting
// - setThreadPriority function implemented and tested
// - Currently testing for tasks failures
//
// Version 1.5.5.1 -(03/13/2019)
// info:
// - 'ipcs' functionality added.
// - Currently testing for tasks failures
//
// Version 1.5.5 -(03/12/2019)
// info:
// - Flash4Hz ticks overflow bug removed with extra if else cases in systickISR
// - 'statof' extra command added for debug purposes (not included in the coursework)
//
// Version 1.5.4 -(03/11/2019)
// info:
// - preempt and sched function working, (round-robin and priority scheduling selection working confirmed)
// - destroythread() working and confirmed, with semaphore handling
// - Shell protected from being killed
//
// Version 1.5.3 -(03/06/2019)
// info:
// - step 13, preemptive scheduler support implemented
// - step 9, modified to add round-robin and priority scheduling selection, confirmation pending
//
// Version 1.5.2 -(02/27/2019)
// info:
// - Lengthyfn() taking too long bug removed,
// - Confirmation of priorities working correctly, previously there was a problem.
//
// Version 1.5.1 -(02/26/2019)
// info:
// - step 8 and 9 added successfully, confirmation pending
// - performance improvement in buffer clear and reset
// - all threads added, shell thread working successfully
//
// Version 1.5-(02/23/2019)
// info:
// - Step 4, 5, 6 and 7 added,
// - svc offset changes #48, (queue struct member is used in processQueue array)
//
// Version 1.4-(02/09/2019)
// info:
/// - Step 1 Added, setStackPt and getStackPt
// - Step 2 and 3 Added, yield implementation and pendsvc call
//
// Version 1.3-(02/05/2019)
// info:
// - External module / hardware specific pin initializations added for 5 push buttons and Leds
// - Test function added for testing the external modules on daughter board
// - Structure defined for control of test function
// - echo command implemented
//
// Version 1.2-(01/26/2019)
// info:
// - command_line function replaces term_getsUart0 function, with backspace bug removed
//
// Version 1.1-(01/21/2019)
// info:
// - added functions to copy string from source to destination buffer
// - uSTRCPY, uSTRCMP and uSTRLEN, custom implementations of string.h library functions
// - string.h library removed
// - stack size reduced from 8K to 1024 bytes
//
// Version 1.0-(01/20/2019)
// info:
// - added user string length and string compare functions
//
//************************************//
//*****************************************************************************//
// //
// STANDARD LIBRARIES AND BOARD SPECIFIC HEADER FILES //
// //
//*****************************************************************************//
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "tm4c123gh6pm.h"
//*****************************************************************************//
// //
// KERNEL DEFINES AND DATA STRUCTURES //
// //
//*****************************************************************************//
//******************* Semaphore Defines **********************//
#define MAX_SEMAPHORES 5 // Maximum number of semaphores
#define MAX_QUEUE_SIZE 5 // Maximum queue size
//******************* Task Defines **********************//
// Task/Thread States
#define STATE_INVALID 0 // No task
#define STATE_UNRUN 1 // Task has never been run
#define STATE_READY 2 // Has run, can resume at any time
#define STATE_DELAYED 3 // Has run, but now awaiting timer
#define STATE_BLOCKED 4 // Has run, but now blocked by semaphore
#define MAX_TASKS 10 // Maximum number of valid tasks
// Processor Clocks
#define CLOCKFREQ 40000000 // Main Clock/BUS Frequency
#define SYSTICKFREQ 1000 // Systick timer Frequency
//******************* Kernel Data Structures **********************//
// Semaphore Data Structure
struct semaphore
{
uint16_t count; // Store Semaphore count
uint16_t queueSize; // Store Queue Size
char semName[15]; // Store Semaphore Name
uint32_t processQueue[MAX_QUEUE_SIZE]; // Store PID of blocked waiting task
} semaphores[MAX_SEMAPHORES];
// Thread Control Block Data Structure
struct _tcb
{
uint8_t state; // For Storing State Values, mentioned above in Macro defines
void *pid; // Used to uniquely identify thread
void *sp; // Location of stack pointer for thread
int8_t priority; // -8 = highest to 7 = lowest
int8_t currentPriority; // Used for priority inheritance
uint32_t ticks; // Ticks until sleep complete
char name[16]; // Store Name of Thread/Task
void *semaphore; // Pointer to the semaphore that is blocking the thread
uint8_t skips; // Skip count for priority calculations
} tcb[MAX_TASKS];
// Service Call ISR cases
enum svc_cases
{
svcYIELD = 100, // Value of yield label in switch case
svcSLEEP = 101, // Value of switch label in switch case
svcWAIT = 102, // Value of wait label in switch case
svcPOST = 103, // Value of post label in switch case
svcKILL = 104, // Value of kill label in switch case
};
// RTOS scheduler Data Structure
struct osScheduler
{
uint8_t preemptiveEnable; // For Setting the Preemptive Scheduler Enable Mode
uint8_t priorityEnable; // For Setting the Priority Scheduler Enable Mode
uint8_t priorityInherit; // For Enabling Priority Inheritance
};
// DS for time calculations
struct timeCalc
{
uint32_t runTime; // Used for storing time taken by task to run
//uint32_t totalTime1; // Used for storing total run time of task till OS is running
uint32_t filterTime; // Used for storing the moving averaged value of run time
uint32_t taskPercentage; // User for storing value of CPU usage for each task
}processTime[MAX_TASKS];
//*****************************************************************************//
// //
// (KERNEL) Function Prototypes //
// //
//*****************************************************************************//
// Typedefs
typedef void (*_fn)(); // Typedef to function pointer for threads
// Kernel main Functions
void rtosInit(); // Function to Initialize RTOS. | retval: void | param: NULL |
int rtosScheduler(); // Function to Configure RTOS Scheduler. | retval: task | param: NULL |
void rtosStart(); // Function to Start the RTOS. | retval: void | param: NULL |
bool createThread(_fn fn, char name[], int priority); // Function to Create Task/Threads. | retval: bool | param: Pointer To Task | param: Task Name | param: Task Priority |
void destroyThread(_fn fn); // Function to Destroy Task/Threads. | retval: void | param: Pointer To Task |
void setThreadPriority(_fn fn, uint8_t priority); // Function to Destroy Task/Threads. | retval: void | param: Task Priority |
void yield(); // Function to yield. | retval: void | param: NULL |
void sleep(uint32_t tick); // Function to set sleep time Interval | retval: void | param: Value of sleep |
// Kernel Helper Functions
uint32_t ret_R0(void); // Function to get value of 1st Argument | retval: uint32 | param: NULL |
uint32_t ret_R1(void); // Function to get value of 2nd Argument | retval: uint32 | param: NULL |
uint32_t ret_R2(void); // Function to get value of 3rt Argument | retval: uint32 | param: NULL |
uint8_t get_svcValue(void); // Function to get value of SVC Inst. | retval: uint8 | param: NULL |
void setStackPt(void* func_stack); // Function to set System Stack Pointer | retval: void | param: PID To Task |
uint32_t* getStackPt(); // Function to get Stack Pointer | retval: Address of SP | param: NULL |
// Synchronization and semaphore functions
void wait(struct semaphore *pSemaphore); // Function to set Wait for a Semaphore | retval: void | param: Pointer to Sem |
void post(struct semaphore *pSemaphore); // Function to set Post for a Semaphore | retval: void | param: Pointer to Sem |
struct semaphore* createSemaphore(char* semName, uint8_t count); // Function to Create Semaphores | retval: structure pointer to sem | param: Pointer to Sem |
// sem: Semaphore
//*****************************************************************************//
// //
// (KERNEL) GLOBAL VARIABLES //
// //
//*****************************************************************************//
// Kernel Variables
uint8_t taskCurrent = 0; // Index of last dispatched task
uint8_t taskCount = 0; // Total number of valid tasks
uint32_t stack[MAX_TASKS][256]; // 1024 byte stack for each thread
uint8_t semaphoreCount = 0; // Store Semaphore Count value
uint32_t* SystemStackPt; // Pointer to the Main Stack pointer
// Loop Variables
uint8_t i, j, k = 0; // Used in svcisr for loop
// SVC Variables
uint32_t* PC_VAL = 0; // Used in svcisr for storing the program counter value, for inline ASM implementation of stack
uint8_t svc_value = 0; // Value of service call by SVC instruction
uint32_t task_pid = 0; // User for storing task PID in svcISR
// Time Calculation Variables
uint32_t startTime = 0; // User for storing start time of thread
uint32_t stopTime = 0; // User for storing stop time of thread
uint32_t totalTime = 0; // User for storing total time taken by thread in given time-slice (80 ms in SytickISR)
uint16_t measureTimeSlice = 0; // User for storing value of measurement time slice in SystickISR
uint8_t TimeCalcEn = 0; // Enable Time Calculations
// Structure Variables (see structure above in Kernel defines and Data Structures )
struct _tcb tcb[MAX_TASKS] = {0}; // Structure array for thread control block DS
struct osScheduler scheduler; // Structure Variable to osScheduler Structure
struct semaphore *SemaphorePt; // Pointer to SemaphorePt Semaphore, declared in kernel space
struct semaphore *keyPressed; // Pointer to keyPressed Semaphore, declared at user space
struct semaphore *keyReleased; // Pointer to keyReleased Semaphore, declared at user space
struct semaphore *flashReq; // Pointer to flashReq Semaphore, declared at user space
struct semaphore *resource; // Pointer to resource Semaphore, declared at user space
//*****************************************************************************//
// //
// (USER) MACRO DEFINITIONS, DIRECTIVES and STRUCTURES //
// //
//*****************************************************************************//
//*******************Debug and Code test defines**********************//
#ifndef DEBUG
//#define DEBUG
#endif
//****************** Bit Banding defines for Pins *********************// (for TM4C123GXL-TIVA-C LAUNCHPAD)
//PORT E
#define PE1 (*((volatile uint32_t *)(0x42000000 + (0x400243FC-0x40000000)*32 + 1*4)))
#define PE2 (*((volatile uint32_t *)(0x42000000 + (0x400243FC-0x40000000)*32 + 2*4)))
#define PE3 (*((volatile uint32_t *)(0x42000000 + (0x400243FC-0x40000000)*32 + 3*4)))
#define PE4 (*((volatile uint32_t *)(0x42000000 + (0x400243FC-0x40000000)*32 + 4*4)))
//Port F
#define PF1 (*((volatile uint32_t *)(0x42000000 + (0x400253FC-0x40000000)*32 + 1*4)))
#define PF2 (*((volatile uint32_t *)(0x42000000 + (0x400253FC-0x40000000)*32 + 2*4)))
#define PF3 (*((volatile uint32_t *)(0x42000000 + (0x400253FC-0x40000000)*32 + 3*4)))
#define PF4 (*((volatile uint32_t *)(0x42000000 + (0x400253FC-0x40000000)*32 + 4*4)))
//Port A
#define PA2 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 2*4)))
#define PA3 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 3*4)))
#define PA4 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 4*4)))
#define PA5 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 5*4)))
#define PA6 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 6*4)))
#define PA7 (*((volatile uint32_t *)(0x42000000 + (0x400043FC-0x40000000)*32 + 7*4)))
//***************************** Board Modules Pins *************************// (for TM4C123GXL-TIVA-C LAUNCHPAD)
#define ONBOARD_RED_LED PF1
#define ONBOARD_BLUE_LED PF2
#define ONBOARD_GREEN_LED PF3
#define ONBOARD_PUSH_BUTTON PF4
//************************ External Modules Pins ***************************// (for EXTERNAL TESTBENCH)
#define RED_LED PE1
#define BLUE_LED ONBOARD_BLUE_LED
#define GREEN_LED PE2
#define YELLOW_LED PE3
#define ORANGE_LED PE4
#define PUSH_BUTTON_0 PA2
#define PUSH_BUTTON_1 PA3
#define PUSH_BUTTON_2 PA4
#define PUSH_BUTTON_3 PA5
#define PUSH_BUTTON_4 PA6
#define BUTTON_L1 PUSH_BUTTON_4
#define BUTTON_L2 PUSH_BUTTON_3
#define BUTTON_R1 PUSH_BUTTON_2
#define BUTTON_R2 PUSH_BUTTON_1
#define BUTTON_R3 PUSH_BUTTON_0
//************************** Project Specific Defines **********************//
// Length of user input string and max number of arguments
#define MAX_SIZE 40
#define MAX_ARGS 20
// Delimiters from ASCII Table, see Table for more info
#define DELIMS ( (string[i] >= 33 && string[i] <= 44) || \
(string[i] >= 46 && string[i] <= 47) || \
(string[i] >= 58 && string[i] <= 64) || \
(string[i] >= 91 && string[i] <= 96) )
// Argument Check macro function
#define ARGS_CHECK(num) (args_updated < num || args_updated > num)
// VT 100 escape sequence defines
#define __CLEAR__LINE__ (const char*)("\033[2K")
#define __RESTORE__CURSOR__POS__ (const char*)("\0338")
#define __SAVE__CURSOR__POS__ (const char*)("\0337")
#define __CURSOR__BACK__ (const char*)("\033[D")
#define __CURSOR__RIGHT__ (const char*)("\033[C")
//*****************************************************************************//
// //
// (USER)Function Prototypes //
// //
//*****************************************************************************//
//Delay and Blocking Functions
void waitMicrosecond(uint32_t us); // Microsecond Delay Function | retval: void | param: NULL |
// UART IO Control functions
void putcUart0(const char c); // Function to Print Char through UART0 | retval: void | param: character |
void putsUart0(const char* str); // Function to Print String through UART0 | retval: void | param: pointer to character |
char getcUart0(void); // Function to get value through UART0 | retval: void | param: void |
void putnUart0(uint32_t Number); // Function to Print number through UART0 | retval: void | param: uint32_t |
// VT100 Terminal Control Functions
void clear_screen(void); // Function which clears the terminal | retval: void | param: void |
void mov_right(uint16_t val); // Moves the Cursor Right in Terminal | retval: void | param: Cursor position |
void set_cursor(uint32_t Line, uint32_t Cols); // Sets Cursor position in Terminal | retval: void | param: Line value | param: Column Value |
// String functions
uint8_t uSTRLEN(const char *string); // Function to calculate string length | retval: length of string | param: string |
uint8_t uSTRCMP(char *string_1, char *string_2); // Function to compare two strings | retval: 0 (true), < 0 (fail) | param: string 1 | param: string 2 |
void uSTRCPY(char *string_dest, char *string_src); // Function to copy string to destination | retval: void | param: destination | param: source |
// Shell / CLI functions
void command_line(void); // Command line function to take inputs from user | retval: void | param: void |
void parse_string(void); // Function to parse strings entered by user user | retval: void | param: void |
int8_t is_command(char* command, uint8_t arg); // Function to enter valid verbs as commands | retval: -1(Fail), 1(Success) | param: verb | param: argument count |
//Project Command Functions
void project_info(void); // Prints the info of the project | retval: void | param: void |
void TIVA_shell(void); // Shell Interpreter / CLI commands function | retval: void | param: void |
void getTaskPid(void); // Function that prints the the task PID | retval: void | param: void |
void getProcessStatus(void); // Task manager function, displays process | retval: void | param: void |
void getIpcs(void); // Prints the Inter-process comms table | retval: void | param: void |
uint8_t readPbs(void); // Functions for reading the test-bench push buttons | retval: PB value | param: void |
void getTaskStatus(char *threadName); // Prints the detailed status of the function | retval: void |param: task name |
int8_t command_search(void); // Function to search for the command | retval: 1 (success), -1(Fail) | param: void |
//Buffer Reset Control Functions
void reset_buffer(void); // Functions which resets local buffer of command line input | retval: void | param: void |
void reset_new_string(void); // Functions for reading the test-bench push buttons | retval: void | param: void |
//Buffer Reset Control Functions
void reset_buffer(void); // Functions for reseting the local string buffer for CLI | retval: void | param: void |
void reset_new_string(void); // Helper function called by the above function | retval: void | param: void |
//*****************************************************************************//
// //
// (USER)GLOBAL VARIABLES //
// //
//*****************************************************************************//
// String variables
char string[MAX_SIZE] = {0}; // Array to store the chars received from UART
char new_string[MAX_ARGS][MAX_SIZE] = {0}; // Array to store the words after dividing the string to tokens
char buff_int[MAX_SIZE] = {0}; // Array buffer to store converted value of integer to char
// Char category variables
uint8_t a[MAX_ARGS] = {0}; // Array to store the record of Alpha characters
uint8_t n[MAX_ARGS] = {0}; // Array to store the record of Numeric characters
uint8_t s[MAX_ARGS] = {0}; // Array to store the record of Special characters
// Argument count variables
uint8_t args_no = 0; // Variable for indexing initial number of arguments
uint8_t args_str = 0; // Variable for indexing the number of characters per argument
uint8_t args_updated = 0; // Variable for indexing final number of arguments, not initialized to zero
// Local Directory for commands
char cmd_DB [20][15] = {"clear","sched","pidof","ps","echo","ipcs","preempt","kill","reboot", "help", "statof", "pi", "info"};
// Local Directory for Thread/Task PIDs
void *tsk_DB[MAX_TASKS] = {0};
char tskName_DB[MAX_TASKS][20] = {0};
//*****************************************************************************//
// //
// (KERNEL) FUNCTIONS AND SUBROUTINES //
// //
//*****************************************************************************//
// Initialize RTOS paramters
void rtosInit()
{
uint8_t i;
// no tasks running
taskCount = 0;
// Default States
scheduler.priorityEnable = 1; // Enable Condition for Priority Scheduler
scheduler.priorityInherit = 1; // Enable Condition for Priority Inheritance
scheduler.preemptiveEnable = 1; // Enable Condition for Preemption
// clear out tcb records
for (i = 0; i < MAX_TASKS; i++)
{
tcb[i].state = STATE_INVALID;
tcb[i].pid = 0;
}
// REQUIRED: initialize systick for 1ms system timer
NVIC_ST_CTRL_R = 0; // Clear Control bit for safe programming
NVIC_ST_CURRENT_R = 0; // Start Value
NVIC_ST_RELOAD_R = 0x9C3F; // Set for 1Khz, (40000000/1000) - 1
NVIC_ST_CTRL_R = NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | NVIC_ST_CTRL_ENABLE; // set for source as clock interrupt enable and enable the timer.
}
// REQUIRED: Implement prioritization to 8 levels
int rtosScheduler()
{
bool ok;
static uint8_t task = 0xFF;
ok = false;
while (!ok)
{
task++;
if (task >= MAX_TASKS)
task = 0;
// Priority Scheduling
if(scheduler.priorityEnable == 1) // Check if Priority condition is enabled (Default)
{
if(tcb[task].state == STATE_READY || tcb[task].state == STATE_UNRUN) // If yes and tasks are read and in UNRUN states
{
if(tcb[task].skips < tcb[task].currentPriority) // Increment skip counts till the time it doesn't become equal to priority value
{
tcb[task].skips++; // Increment skips
ok = false; // Optional, for better readability
}
else if(tcb[task].skips >= tcb[task].currentPriority) // If greater than equal to current priority value
{
tcb[task].skips = 0; // Clear Skip count
ok = (tcb[task].state == STATE_READY || tcb[task].state == STATE_UNRUN); // Update value of 'ok' to get of the loop
}
}
}
// Round-Robin Scheduling
else // In Else condition it goes round-robin where everyone gets a fair chance
{
tcb[task].skips = 0; // Clear Skip counts if previously coming from Priority Scheduler
ok = (tcb[task].state == STATE_READY || tcb[task].state == STATE_UNRUN); // Update value of 'ok' to get of the loop
}
}
return task;
}
void rtosStart()
{
// REQUIRED: add code to call the first task to be run
_fn fn;
// Store Thread/Task PIDs in Local Database
for(i = 0; i<MAX_TASKS; i++)
{
tsk_DB[i] = tcb[i].pid; // Store Thread PID to directory
uSTRCPY(tskName_DB[i],tcb[i].name);
}
// Add code to initialize the SP with tcb[task_current].sp;
SystemStackPt = getStackPt(); // Store the first value of System/processor SP
taskCurrent = rtosScheduler(); // Run Scheduler
setStackPt(tcb[taskCurrent].sp); // Set SP to thread SP
fn = (_fn)tcb[taskCurrent].pid; // Store the PID current task scheduled from RTOS scheduler to the function pointer
tcb[taskCurrent].state = STATE_READY; // Make Task Current state ready, Initially all are in UNRUN State, see createthread()
(*fn)(); // Run First scheduled Task for first Time (scheduled from rtosScheduler)
}
bool createThread(_fn fn, char name[], int priority)
{
bool ok = false;
uint8_t i = 0;
bool found = false;
priority = priority + 8;
// REQUIRED: store the thread name
// add task if room in task list
if (taskCount < MAX_TASKS)
{
// make sure fn not already in list (prevent re-entrancy)
while (!found && (i < MAX_TASKS))
{
found = (tcb[i++].pid == fn);
}
if (!found)
{
// find first available tcb record
i = 0;
while (tcb[i].state != STATE_INVALID) {i++;}
tcb[i].state = STATE_UNRUN; // Set the initial state as UNRUN
tcb[i].pid = fn; // Set the address of the function as PID
tcb[i].sp = &stack[i][255]; // Point to the user stack
tcb[i].priority = priority; // Set the priority as received priority as argument
tcb[i].currentPriority = priority; // Used in priority inversion
tcb[i].skips = 0; // Initial skip count is 0 for all tasks
uSTRCPY(tcb[i].name, name); // Store the name of the task
// increment task count
taskCount++;
ok = true;
}
}
// REQUIRED: allow tasks switches again
return ok;
}
//REQUIRED: modify this function to destroy a thread
// REQUIRED: remove any pending semaphore waiting
void destroyThread(_fn fn)
{
__asm(" SVC #104"); // Execute SVC instruction for Service call, triggers svCallIsr()
}
// REQUIRED: modify this function to set a thread priority
void setThreadPriority(_fn fn, uint8_t priority)
{
uint8_t stp = 0;
priority = priority + 8; // Bias Priorities by 8, since they range from -8 to 8
for(stp=0; stp<taskCount; stp++)
{
if(tcb[stp].pid == fn) // Check if PID returned from argument is in TCB pid table
{
tcb[stp].currentPriority = priority; // If found then set current priority to argument priority
break;
}
}
}
// Function to create semaphores
struct semaphore* createSemaphore(char* semName, uint8_t count)
{
struct semaphore *pSemaphore = 0;
if (semaphoreCount < MAX_SEMAPHORES)
{
pSemaphore = &semaphores[semaphoreCount++]; // Give the address of the semaphore to the semaphore pointer
pSemaphore->count = count; // Set Semaphore count from the arguments
uSTRCPY(pSemaphore->semName, semName); // Record Semaphore Name
}
return pSemaphore;
}
// REQUIRED: modify this function to yield execution back to scheduler using pendsv
// push registers, call scheduler, pop registers, return to new function
void yield()
{
__asm(" SVC #100"); // Execute SVC instruction for Service call, triggers svCallIsr()
}
// REQUIRED: modify this function to support 1ms system timer
// execution yielded back to scheduler until time elapses using pendsv
// push registers, set state to delayed, store timeout, call scheduler, pop registers,
// return to new function (separate unrun or ready processing)
void sleep(uint32_t tick)
{
__asm(" SVC #101"); // Execute SVC instruction for Service call, triggers svCallIsr()
}
// REQUIRED: modify this function to wait a semaphore with priority inheritance
// return if avail (separate unrun or ready processing), else yield to scheduler using pendsv
void wait(struct semaphore *pSemaphore)
{
__asm(" SVC #102"); // Execute SVC instruction for Service call, triggers svCallIsr()
}
// REQUIRED: modify this function to signal a semaphore is available using pendsv
void post(struct semaphore *pSemaphore)
{
__asm(" SVC #103"); // Execute SVC instruction for Service call, triggers svCallIsr()
}
// REQUIRED: modify this function to add support for the system timer
// REQUIRED: in preemptive code, add code to request task switch
void systickIsr(void)
{
uint8_t tsk = 0; // Variable for task number loop
uint8_t firstUpdate = 1; // Variable for Moving Average Filter first update
// Sleep function support
for(tsk=0; tsk < MAX_TASKS; tsk++)
{
if(tcb[tsk].state == STATE_DELAYED) // Check If state is DELAYED
{
if(tcb[tsk].ticks > 0)
tcb[tsk].ticks--; // Decrement ticks only if ticks are greater than 0
//if(tcb[tsk].ticks == 0) // If ticks are equal to zero then make state READY
else
tcb[tsk].state = STATE_READY;
}
}
// CPU Usage measurement for different threads
measureTimeSlice++; // Increment measurement time slice variable till it reaches 100 (100ms as systick = 1KHz)
if(measureTimeSlice == 100) // Check if timeslice is equal 100
{
#if 0
// Measure time when entered in systickISR if entered before task switch
stopTime = TIMER1_TAV_R;
TIMER1_CTL_R &= ~TIMER_CTL_TAEN;
processTime[taskCurrent].runTime = stopTime - startTime;
#endif
// Filter run time data (Moving Average), Implementation from Fall-2018, EE5314 Project (given by Dr.Jason Losh)
for(tsk=0; tsk<MAX_TASKS; tsk++)
{
if(firstUpdate)
{
processTime[tsk].filterTime = processTime[tsk].runTime;
firstUpdate = 0;
}
else
processTime[tsk].filterTime = processTime[tsk].filterTime * 0.9 + processTime[tsk].runTime * (1 - 0.9); // Alpha = 0.9
}
totalTime = 0;
// Calculate Total Time
for(tsk=0; tsk<MAX_TASKS; tsk++)
{
totalTime = totalTime + processTime[tsk].filterTime;
//processTime[tsk].totalTime1 = processTime[tsk].totalTime1 \
+ processTime[tsk].filterTime; // Optionally used to calculate total time a task has been running, while system is on
}
// Calculate CPU %age
for(tsk=0; tsk<MAX_TASKS; tsk++)
{
processTime[tsk].taskPercentage = (processTime[tsk].filterTime * 10000) / totalTime; // Multiply by 10000 to preserve decimal upto two place
processTime[tsk].runTime = 0; // clear runTime variable
}
measureTimeSlice = 0; // clear time slice variable
}
// Preemptive scheduler support
// Make sure there is at least one task with READY state as this is the first ISR to run,
// in rtosInit() or will switch tasks that don't exist and will get into fault ISR.
if(scheduler.preemptiveEnable && taskCurrent != 0)
NVIC_INT_CTRL_R= NVIC_INT_CTRL_PEND_SV;
}
// REQUIRED: in coop and preemptive, modify this function to add support for task switching
// REQUIRED: process UNRUN and READY tasks differently
void pendSvIsr(void)
{
__asm(" PUSH {R4-R11}"); // Push Register list
tcb[taskCurrent].sp = getStackPt(); // save stack pointer in tcb
setStackPt(SystemStackPt); // set stack pointer to System Stack pointer
// stop the timer
stopTime = TIMER1_TAV_R; // Save Final Value of Timer register
TIMER1_CTL_R &= ~TIMER_CTL_TAEN; // Stop Timer
TIMER1_TAV_R = 0; // Set Timer Zero
// Timer Measurements END
// Calculate time difference
if(tcb[taskCurrent].state != STATE_INVALID && TimeCalcEn == 1) // Calculate for everyone but Invalid States and Time calculation enable bit is set
{
processTime[taskCurrent].runTime = stopTime - startTime; // Store Time Difference
stopTime = 0;
startTime = 0;
}
#if 1 // Optional Logic to disable time calculations in blocked state (1:Enable, 0:Disable)
// No calculations during blocked state
if(tcb[taskCurrent].state == STATE_BLOCKED)
{
processTime[taskCurrent].taskPercentage = 0; // Clear percentage time
processTime[taskCurrent].filterTime = 0; // clear averaged time
processTime[taskCurrent].runTime = 0; // clear task run time
}
#endif
//************************************************** Context Switch ************************************************************//
taskCurrent = rtosScheduler(); // Call RTOS Scheduler to Switch Task
// Time Measurements Start
TIMER1_CTL_R |= TIMER_CTL_TAEN; // Start the timer
startTime = TIMER1_TAV_R; // Save initial Value of Timer register
//************************************************ STACK OPERATIONS AND ALOCATIONS *************************************************//
if(tcb[taskCurrent].state == STATE_READY) // If in Ready State
{
setStackPt(tcb[taskCurrent].sp); // Set Thread SP to Processor SP
__asm(" POP {R4-R11}"); // POP Register List
}
else if(tcb[taskCurrent].state == STATE_UNRUN) // If in Unrun State, give task a new stack, as if its already is running
{
tcb[taskCurrent].state = STATE_READY; // Make State as Ready
// In-line ASM Implementation
#if 1 // Two Optional methods for thread stack allocation (1:In-line ASM, 0:Stack seeding)
setStackPt(tcb[taskCurrent].sp);
__asm(" MOV R0, #0x01000000" ); // 0x01000000. XPSR
__asm(" PUSH {R0}" ); // Push XPSR
PC_VAL = tcb[taskCurrent].pid; // PC value, PC at thread, PID of thread
__asm(" PUSH {R0}" ); // Push PC
__asm(" PUSH {LR}" ); // Push LR
__asm(" PUSH {R12}" ); // Push R12
__asm(" PUSH {R0-R3}" ); // Push R0 to R3
__asm(" MOVW R8, #0xFFF9" ); // Move LSB to R8 register, adjusted as per compiler pushes
__asm(" MOVT R8, #0xFFFF" ); // Move MSB to R8 register
__asm(" PUSH {R8}" ); // Push value of LR, saved in R8, (hard coded) or saved at starting of pendSvIsr
__asm(" PUSH {R3}" ); // Push compiler register
#else
// Putting values in Thread Stack Better for Debugging
stack[taskCurrent][255] = 0x01000000; // XPSR,
stack[taskCurrent][254] = (uint32_t)tcb[taskCurrent].pid; // PC, PID of Thread
stack[taskCurrent][253] = 15; // LR, and debug value
stack[taskCurrent][252] = 14; // R12, and debug value
stack[taskCurrent][251] = 13; // R3, and debug value
stack[taskCurrent][250] = 12; // R2, and debug value
stack[taskCurrent][249] = 11; // R1, and debug value
stack[taskCurrent][248] = 10; // R0, and debug value
stack[taskCurrent][247] = 0xFFFFFFF9; // Value of LR, for compiler push
stack[taskCurrent][246] = (uint32_t)"R3"; // Debug Value, for compiler push
tcb[taskCurrent].sp = &stack[taskCurrent][246]; // Point Thread SP to stop of the thread Stack
setStackPt(tcb[taskCurrent].sp); // Set Thread SP to processor SP
#endif
}
}
// Function for getting the value of SVC instruction
// Offset was calculated by seeing the previous value of Program counter when on,
// respective SVC instruction (SVC, #100...) using a breakpoint and then finding that,
// value, [when reached to this function (putting a break point)], in SP further offset,
// by 2 since SVC is 2 byte instruction.
uint8_t get_svcValue(void)
{
__asm(" MOV R0, SP" ); // Move SP to R0, (address)
__asm(" ADD R0, #48" ); // ADD offset , (address)
__asm(" LDR R0, [R0]" ); // Load offset to R0 (value)
__asm(" SUBS R0, #2" ); // Subtract 2 from R0 (value), 2 byte offset of SVC instruction
__asm(" LDR R0, [R0]" ); // Load value to R0 (value)
__asm(" BX LR" );
return 0;
}
// Empty function for returning the value of R0, 1st Argument to function
uint32_t ret_R0(void)
{
__asm(" BX LR" );
return 0;
}
// Empty function for returning the value of R1 which is moved to R0, 2nd Argument to function
uint32_t ret_R1(void)
{
__asm(" MOV R0,R1" );
__asm(" BX LR" );
return 0;
}
// Empty function for returning the value of R2 which is moved to R0, 3nd Argument to function
uint32_t ret_R2(void)
{
__asm(" MOV R0,R2" );
__asm(" BX LR" );
return 0;
}
// REQUIRED: modify this function to add support for the service call
// REQUIRED: in preemptive code, add code to handle synchronization primitives
void svCallIsr(void)
{
uint32_t R0 = ret_R0(); // Get value of r0
uint32_t R1 = ret_R1(); // Get value of r1
uint32_t R2 = ret_R2(); // Get value of r2
svc_value = get_svcValue(); // Get SVC value
switch(svc_value) // Switch Case for SVC value
{
case svcYIELD:
tcb[taskCurrent].state = STATE_READY; // Set task as ready
NVIC_INT_CTRL_R= NVIC_INT_CTRL_PEND_SV; // Set pendsv bit to call pendsvISR for task switch
break;
case svcSLEEP:
tcb[taskCurrent].ticks = R0; // Set sleep timeout value
tcb[taskCurrent].state = STATE_DELAYED; // Set state as delayed, it can't be scheduled till the time it is not in ready state
NVIC_INT_CTRL_R= NVIC_INT_CTRL_PEND_SV; // Set pendsv bit to call pendsvISR for task switch
break;
case svcWAIT:
SemaphorePt = (struct semaphore*)R0; // Get the pointer to the semaphore