Latest
Dependencies: serial_terminal sample_hardware PLL_Config SDCard BMP280 Networkbits TextLCD SDBlockDevice
main.cpp@32:8c9d8f2dfe89, 2019-01-03 (annotated)
- Committer:
- Swabey89
- Date:
- Thu Jan 03 10:33:33 2019 +0000
- Revision:
- 32:8c9d8f2dfe89
- Parent:
- 31:087e295cc859
Latest
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Swabey89 | 7:e2bf2d703867 | 1 | #include "mbed.h" |
Swabey89 | 31:087e295cc859 | 2 | #include <stm32f4xx.h> |
Swabey89 | 1:31c7b4ab552b | 3 | #include "sample_hardware.hpp" |
Swabey89 | 21:2c438eeaab14 | 4 | #include "Networking.hpp" |
Swabey89 | 5:956984cbe447 | 5 | #include "serial_terminal.hpp" |
Swabey89 | 6:a5394c9e5927 | 6 | #include "SDCard.hpp" |
Swabey89 | 5:956984cbe447 | 7 | #include "rtos.h" |
Swabey89 | 11:3ad0327e8c9f | 8 | #include "events/mbed_events.h" |
Swabey89 | 8:c81b0ff8b822 | 9 | #include "LCDdisplay.hpp" |
Swabey89 | 31:087e295cc859 | 10 | //#include "PLL_Config.c" |
Swabey89 | 5:956984cbe447 | 11 | |
Swabey89 | 24:81981815ef20 | 12 | //Defines TEST FOR SD CARD MOUNT AND UNMOUNT |
Swabey89 | 24:81981815ef20 | 13 | #define EDGE_FALLEN 0 |
Swabey89 | 24:81981815ef20 | 14 | #define EDGE_RISEN 1 |
Swabey89 | 19:88d8359306a4 | 15 | |
Swabey89 | 10:0fffc988d325 | 16 | //Signals |
Swabey89 | 8:c81b0ff8b822 | 17 | #define TAKE_SAMPLE 1 |
Swabey89 | 19:88d8359306a4 | 18 | #define STORE_DATA 2 |
Swabey89 | 10:0fffc988d325 | 19 | |
Swabey89 | 24:81981815ef20 | 20 | |
Swabey89 | 17:ead43c1b729d | 21 | //Global variables |
Swabey89 | 19:88d8359306a4 | 22 | |
Swabey89 | 27:bb8d4c883e1b | 23 | |
Swabey89 | 28:7fccaef8fa72 | 24 | unsigned int newestIndex = BUFFERSIZE-1; //First time it is incremented, it will be 0 |
Swabey89 | 28:7fccaef8fa72 | 25 | unsigned int oldestIndex = BUFFERSIZE-1; |
Swabey89 | 17:ead43c1b729d | 26 | FILE* fp; |
Swabey89 | 17:ead43c1b729d | 27 | FATFileSystem* fs; |
Swabey89 | 10:0fffc988d325 | 28 | |
Swabey89 | 19:88d8359306a4 | 29 | //Shared mutable variables VOLATILE |
Swabey89 | 25:831dc928ccde | 30 | bool sd_init; //is it? |
Swabey89 | 28:7fccaef8fa72 | 31 | bool logging = false; |
Swabey89 | 30:7873beb54744 | 32 | bool sampling = true; |
Swabey89 | 22:d9cbbbf3cf69 | 33 | float sample_rate = 15; //is it? |
Swabey89 | 17:ead43c1b729d | 34 | struct tm* timeData; |
Swabey89 | 18:3edfb9152b05 | 35 | char cmdBuffer[256]; |
Swabey89 | 19:88d8359306a4 | 36 | sensorData buffer[BUFFERSIZE]; |
Swabey89 | 17:ead43c1b729d | 37 | RawSerial* pc; |
Swabey89 | 8:c81b0ff8b822 | 38 | |
Swabey89 | 19:88d8359306a4 | 39 | //Thread synchronisation primatives |
Swabey89 | 19:88d8359306a4 | 40 | Semaphore spaceAvailable(BUFFERSIZE); |
Swabey89 | 28:7fccaef8fa72 | 41 | Semaphore samplesInBuffer(0, BUFFERSIZE); |
Swabey89 | 19:88d8359306a4 | 42 | Mutex bufferLock; |
Swabey89 | 19:88d8359306a4 | 43 | |
Swabey89 | 8:c81b0ff8b822 | 44 | //Queues |
Swabey89 | 31:087e295cc859 | 45 | EventQueue SDqueue(1024*EVENTS_EVENT_SIZE); //changed from 32 |
Swabey89 | 11:3ad0327e8c9f | 46 | EventQueue LCDqueue(32*EVENTS_EVENT_SIZE); |
Swabey89 | 17:ead43c1b729d | 47 | EventQueue serialqueue(32*EVENTS_EVENT_SIZE); |
Swabey89 | 1:31c7b4ab552b | 48 | |
Swabey89 | 31:087e295cc859 | 49 | //TEST |
Swabey89 | 31:087e295cc859 | 50 | EventQueue printQueue(256*EVENTS_EVENT_SIZE); |
Swabey89 | 31:087e295cc859 | 51 | |
Swabey89 | 29:806e9281af2f | 52 | |
Swabey89 | 29:806e9281af2f | 53 | |
Swabey89 | 1:31c7b4ab552b | 54 | //Threads |
Swabey89 | 19:88d8359306a4 | 55 | Thread producer_thread(osPriorityHigh); |
Swabey89 | 19:88d8359306a4 | 56 | Thread consumer_thread; |
Swabey89 | 19:88d8359306a4 | 57 | Thread serial_thread(osPriorityAboveNormal); |
Swabey89 | 29:806e9281af2f | 58 | Thread SDqueue_thread; //take out queue in name? |
Swabey89 | 11:3ad0327e8c9f | 59 | Thread LCDqueue_thread; |
Swabey89 | 29:806e9281af2f | 60 | Thread network_thread; |
Swabey89 | 0:4afd4940a189 | 61 | |
Swabey89 | 24:81981815ef20 | 62 | //TEST FOR SD CARD |
Swabey89 | 24:81981815ef20 | 63 | Thread SDmount_thread; |
Swabey89 | 24:81981815ef20 | 64 | |
Swabey89 | 31:087e295cc859 | 65 | //TEST FOR PRINTF |
Swabey89 | 31:087e295cc859 | 66 | |
Swabey89 | 31:087e295cc859 | 67 | |
Swabey89 | 17:ead43c1b729d | 68 | //Timers |
Swabey89 | 8:c81b0ff8b822 | 69 | Ticker sample; |
Swabey89 | 10:0fffc988d325 | 70 | |
Swabey89 | 17:ead43c1b729d | 71 | //Function prototypes |
Swabey89 | 8:c81b0ff8b822 | 72 | void sampleISR(void); |
Swabey89 | 19:88d8359306a4 | 73 | void sampleProducer(void); |
Swabey89 | 19:88d8359306a4 | 74 | void sampleConsumer(void); |
Swabey89 | 11:3ad0327e8c9f | 75 | void serialISR(void); |
Swabey89 | 19:88d8359306a4 | 76 | void serialData(void); |
Swabey89 | 11:3ad0327e8c9f | 77 | |
Swabey89 | 24:81981815ef20 | 78 | |
Swabey89 | 24:81981815ef20 | 79 | |
Swabey89 | 24:81981815ef20 | 80 | //TEST FOR SD CARD MOUNT AND UNMOUNT |
Swabey89 | 24:81981815ef20 | 81 | Timeout userswTimeOut; |
Swabey89 | 24:81981815ef20 | 82 | int userswState = EDGE_FALLEN; |
Swabey89 | 24:81981815ef20 | 83 | InterruptIn usersw(USER_BUTTON); |
Swabey89 | 24:81981815ef20 | 84 | void userswTimeOutHandler(); |
Swabey89 | 24:81981815ef20 | 85 | void userswRisingEdge(); |
Swabey89 | 24:81981815ef20 | 86 | void userswFallingEdge(); |
Swabey89 | 24:81981815ef20 | 87 | void SDmount(); |
Swabey89 | 24:81981815ef20 | 88 | |
Swabey89 | 25:831dc928ccde | 89 | Mutex printlock; |
Swabey89 | 25:831dc928ccde | 90 | Mutex LCDlock; |
Swabey89 | 25:831dc928ccde | 91 | Mutex timeLock; |
Swabey89 | 25:831dc928ccde | 92 | Mutex SDlock; |
Swabey89 | 24:81981815ef20 | 93 | |
Swabey89 | 24:81981815ef20 | 94 | |
Swabey89 | 27:bb8d4c883e1b | 95 | //TEST FOR BUFFER CHANGES |
Swabey89 | 28:7fccaef8fa72 | 96 | unsigned int saveIndex = BUFFERSIZE-1; |
Swabey89 | 28:7fccaef8fa72 | 97 | |
Swabey89 | 28:7fccaef8fa72 | 98 | int32_t Nspaces = BUFFERSIZE; |
Swabey89 | 28:7fccaef8fa72 | 99 | int32_t Nsamples; |
Swabey89 | 27:bb8d4c883e1b | 100 | |
Swabey89 | 27:bb8d4c883e1b | 101 | |
Swabey89 | 29:806e9281af2f | 102 | //TEST FOR WATCHDOG |
Swabey89 | 29:806e9281af2f | 103 | char threadstates = 0; |
Swabey89 | 29:806e9281af2f | 104 | |
Swabey89 | 29:806e9281af2f | 105 | Timeout producer_tout; |
Swabey89 | 29:806e9281af2f | 106 | Timeout consumer_tout; |
Swabey89 | 29:806e9281af2f | 107 | Timeout serial_tout; |
Swabey89 | 29:806e9281af2f | 108 | Timeout SD_tout; |
Swabey89 | 29:806e9281af2f | 109 | Timeout LCD_tout; |
Swabey89 | 29:806e9281af2f | 110 | Timeout network_tout; |
Swabey89 | 29:806e9281af2f | 111 | |
Swabey89 | 29:806e9281af2f | 112 | Thread watchdog_thread(osPriorityHigh); |
Swabey89 | 29:806e9281af2f | 113 | |
Swabey89 | 31:087e295cc859 | 114 | //TSET FOR PRINTF |
Swabey89 | 31:087e295cc859 | 115 | Thread printf_thread; |
Swabey89 | 31:087e295cc859 | 116 | |
Swabey89 | 29:806e9281af2f | 117 | void producer_toutISR(void); |
Swabey89 | 29:806e9281af2f | 118 | void consumer_toutISR(void); |
Swabey89 | 29:806e9281af2f | 119 | void serial_toutISR(void); |
Swabey89 | 29:806e9281af2f | 120 | void SD_toutISR(void); |
Swabey89 | 29:806e9281af2f | 121 | void LCD_toutISR(void); |
Swabey89 | 29:806e9281af2f | 122 | void network_toutISR(void); |
Swabey89 | 29:806e9281af2f | 123 | void watchdog(void); |
Swabey89 | 29:806e9281af2f | 124 | |
Swabey89 | 31:087e295cc859 | 125 | void PLL_Config(void); |
Swabey89 | 31:087e295cc859 | 126 | |
Swabey89 | 29:806e9281af2f | 127 | osThreadId main_thread; |
Swabey89 | 29:806e9281af2f | 128 | |
Swabey89 | 29:806e9281af2f | 129 | #define PRODUCER 1<<0 |
Swabey89 | 29:806e9281af2f | 130 | #define CONSUMER 1<<1 |
Swabey89 | 29:806e9281af2f | 131 | #define SERIAL 1<<2 |
Swabey89 | 29:806e9281af2f | 132 | #define SD 1<<3 |
Swabey89 | 29:806e9281af2f | 133 | #define LCD 1<<4 |
Swabey89 | 29:806e9281af2f | 134 | #define NETWORK 1<<5 |
Swabey89 | 29:806e9281af2f | 135 | |
Swabey89 | 15:8af9672a6778 | 136 | int main() { |
Swabey89 | 31:087e295cc859 | 137 | PLL_Config(); |
Swabey89 | 29:806e9281af2f | 138 | main_thread = Thread::gettid(); |
Swabey89 | 17:ead43c1b729d | 139 | timeData = new tm; |
Swabey89 | 31:087e295cc859 | 140 | pc = new RawSerial(USBTX, USBRX, 115200); |
Swabey89 | 8:c81b0ff8b822 | 141 | |
Swabey89 | 18:3edfb9152b05 | 142 | //Initialisations |
Swabey89 | 17:ead43c1b729d | 143 | SDcard(); |
Swabey89 | 9:fa8a35d9d6c0 | 144 | |
Swabey89 | 1:31c7b4ab552b | 145 | //Power on self test |
Swabey89 | 1:31c7b4ab552b | 146 | post(); |
Swabey89 | 31:087e295cc859 | 147 | |
Swabey89 | 18:3edfb9152b05 | 148 | //Start threads |
Swabey89 | 18:3edfb9152b05 | 149 | SDqueue_thread.start(callback(&SDqueue, &EventQueue::dispatch_forever)); |
Swabey89 | 18:3edfb9152b05 | 150 | LCDqueue_thread.start(callback(&LCDqueue, &EventQueue::dispatch_forever)); |
Swabey89 | 19:88d8359306a4 | 151 | serial_thread.start(callback(&serialqueue, &EventQueue::dispatch_forever)); |
Swabey89 | 29:806e9281af2f | 152 | network_thread.start(network); |
Swabey89 | 19:88d8359306a4 | 153 | producer_thread.start(sampleProducer); |
Swabey89 | 19:88d8359306a4 | 154 | consumer_thread.start(sampleConsumer); |
Swabey89 | 3:b1583f309b43 | 155 | |
Swabey89 | 31:087e295cc859 | 156 | //TEST |
Swabey89 | 31:087e295cc859 | 157 | LCDqueue.call_every(5000, LCD_display); |
Swabey89 | 31:087e295cc859 | 158 | |
Swabey89 | 24:81981815ef20 | 159 | //TEST FOR SD CARD |
Swabey89 | 31:087e295cc859 | 160 | //SDmount_thread.start(SDmount); |
Swabey89 | 24:81981815ef20 | 161 | |
Swabey89 | 29:806e9281af2f | 162 | //TEST FOR WATCGDOG |
Swabey89 | 29:806e9281af2f | 163 | watchdog_thread.start(watchdog); |
Swabey89 | 29:806e9281af2f | 164 | |
Swabey89 | 31:087e295cc859 | 165 | //TEST FOR PRINTFQUEUE |
Swabey89 | 31:087e295cc859 | 166 | printf_thread.start(callback(&printQueue, &EventQueue::dispatch_forever)); |
Swabey89 | 31:087e295cc859 | 167 | |
Swabey89 | 28:7fccaef8fa72 | 168 | |
Swabey89 | 18:3edfb9152b05 | 169 | //Attach ISRs |
Swabey89 | 28:7fccaef8fa72 | 170 | sample.attach(&sampleISR, sample_rate); //Allow sampling to start |
Swabey89 | 11:3ad0327e8c9f | 171 | pc->attach(serialISR, Serial::RxIrq); |
Swabey89 | 15:8af9672a6778 | 172 | |
Swabey89 | 24:81981815ef20 | 173 | //TEST FOR SD CARD MOUNT AND UNMOUNT |
Swabey89 | 29:806e9281af2f | 174 | usersw.rise(&userswRisingEdge); |
Swabey89 | 24:81981815ef20 | 175 | |
Swabey89 | 1:31c7b4ab552b | 176 | //Flash to indicate goodness |
Swabey89 | 1:31c7b4ab552b | 177 | while(true) { |
Swabey89 | 31:087e295cc859 | 178 | //greenLED = !greenLED; |
Swabey89 | 31:087e295cc859 | 179 | //Thread::wait(500); |
Swabey89 | 0:4afd4940a189 | 180 | } |
Swabey89 | 0:4afd4940a189 | 181 | } |
Swabey89 | 1:31c7b4ab552b | 182 | |
Swabey89 | 19:88d8359306a4 | 183 | /* |
Swabey89 | 19:88d8359306a4 | 184 | FUNCITONS BELOW NEED MOVING? |
Swabey89 | 19:88d8359306a4 | 185 | */ |
Swabey89 | 19:88d8359306a4 | 186 | |
Swabey89 | 8:c81b0ff8b822 | 187 | void sampleISR() |
Swabey89 | 8:c81b0ff8b822 | 188 | { |
Swabey89 | 19:88d8359306a4 | 189 | producer_thread.signal_set(TAKE_SAMPLE); |
Swabey89 | 8:c81b0ff8b822 | 190 | } |
Swabey89 | 1:31c7b4ab552b | 191 | |
Swabey89 | 11:3ad0327e8c9f | 192 | void serialISR() |
Swabey89 | 11:3ad0327e8c9f | 193 | { |
Swabey89 | 11:3ad0327e8c9f | 194 | pc->attach(NULL, Serial::RxIrq); |
Swabey89 | 19:88d8359306a4 | 195 | serialqueue.call(serialData); |
Swabey89 | 11:3ad0327e8c9f | 196 | } |
Swabey89 | 1:31c7b4ab552b | 197 | |
Swabey89 | 19:88d8359306a4 | 198 | void serialData() |
Swabey89 | 12:3a54cbaa714c | 199 | { |
Swabey89 | 17:ead43c1b729d | 200 | static int i = 0; |
Swabey89 | 29:806e9281af2f | 201 | |
Swabey89 | 11:3ad0327e8c9f | 202 | if (pc->readable()) |
Swabey89 | 11:3ad0327e8c9f | 203 | { |
Swabey89 | 18:3edfb9152b05 | 204 | cmdBuffer[i] = pc->getc(); |
Swabey89 | 29:806e9281af2f | 205 | if (i != 29) |
Swabey89 | 11:3ad0327e8c9f | 206 | { |
Swabey89 | 29:806e9281af2f | 207 | |
Swabey89 | 29:806e9281af2f | 208 | if (cmdBuffer[i] == '\b') |
Swabey89 | 29:806e9281af2f | 209 | { |
Swabey89 | 29:806e9281af2f | 210 | i = (i ? i-1 : 0); |
Swabey89 | 29:806e9281af2f | 211 | } |
Swabey89 | 29:806e9281af2f | 212 | else if (cmdBuffer[i] == '\r') |
Swabey89 | 29:806e9281af2f | 213 | { |
Swabey89 | 29:806e9281af2f | 214 | cmdBuffer[i+1]==NULL; |
Swabey89 | 29:806e9281af2f | 215 | serialqueue.call(serialterm); |
Swabey89 | 29:806e9281af2f | 216 | i = 0; |
Swabey89 | 29:806e9281af2f | 217 | } |
Swabey89 | 29:806e9281af2f | 218 | else i++; |
Swabey89 | 29:806e9281af2f | 219 | } |
Swabey89 | 29:806e9281af2f | 220 | else |
Swabey89 | 29:806e9281af2f | 221 | { |
Swabey89 | 28:7fccaef8fa72 | 222 | serialqueue.call(serialterm); |
Swabey89 | 29:806e9281af2f | 223 | i = 0; |
Swabey89 | 11:3ad0327e8c9f | 224 | } |
Swabey89 | 11:3ad0327e8c9f | 225 | } |
Swabey89 | 11:3ad0327e8c9f | 226 | pc->attach(serialISR, Serial::RxIrq); |
Swabey89 | 11:3ad0327e8c9f | 227 | } |
Swabey89 | 19:88d8359306a4 | 228 | |
Swabey89 | 19:88d8359306a4 | 229 | |
Swabey89 | 19:88d8359306a4 | 230 | void sampleProducer() |
Swabey89 | 19:88d8359306a4 | 231 | { |
Swabey89 | 19:88d8359306a4 | 232 | while(true) |
Swabey89 | 19:88d8359306a4 | 233 | { |
Swabey89 | 19:88d8359306a4 | 234 | //High priority thread |
Swabey89 | 29:806e9281af2f | 235 | Thread::signal_wait(TAKE_SAMPLE); |
Swabey89 | 29:806e9281af2f | 236 | //wd_thread.signal_set(PROD_SIGNAL); |
Swabey89 | 31:087e295cc859 | 237 | //prod_stat = 0; |
Swabey89 | 28:7fccaef8fa72 | 238 | Nspaces = spaceAvailable.wait(0); //Non-blocking |
Swabey89 | 29:806e9281af2f | 239 | bufferLock.lock(); |
Swabey89 | 31:087e295cc859 | 240 | producer_tout.attach(producer_toutISR, TOUT_TIME_DEF); |
Swabey89 | 31:087e295cc859 | 241 | |
Swabey89 | 28:7fccaef8fa72 | 242 | //Update buffer |
Swabey89 | 32:8c9d8f2dfe89 | 243 | |
Swabey89 | 32:8c9d8f2dfe89 | 244 | if ((newestIndex == oldestIndex) && (Nspaces==0)) |
Swabey89 | 28:7fccaef8fa72 | 245 | { |
Swabey89 | 32:8c9d8f2dfe89 | 246 | //printQueue.call(printf, "oldest index being increased\n\r"); |
Swabey89 | 28:7fccaef8fa72 | 247 | oldestIndex = (oldestIndex+1) % BUFFERSIZE; |
Swabey89 | 31:087e295cc859 | 248 | } |
Swabey89 | 31:087e295cc859 | 249 | |
Swabey89 | 32:8c9d8f2dfe89 | 250 | newestIndex = (newestIndex+1) % BUFFERSIZE; //CIRCULAR |
Swabey89 | 31:087e295cc859 | 251 | /* |
Swabey89 | 19:88d8359306a4 | 252 | buffer[newestIndex].updatetemp(sensor.getTemperature()); |
Swabey89 | 19:88d8359306a4 | 253 | buffer[newestIndex].updatepress(sensor.getPressure()); |
Swabey89 | 19:88d8359306a4 | 254 | buffer[newestIndex].updatelight(adcIn.read()); |
Swabey89 | 31:087e295cc859 | 255 | buffer[newestIndex].updateTime(); |
Swabey89 | 31:087e295cc859 | 256 | */ |
Swabey89 | 31:087e295cc859 | 257 | |
Swabey89 | 31:087e295cc859 | 258 | double temp_r = sensor.getTemperature(); |
Swabey89 | 31:087e295cc859 | 259 | double press_r = sensor.getPressure(); |
Swabey89 | 31:087e295cc859 | 260 | float light_r = adcIn.read(); |
Swabey89 | 31:087e295cc859 | 261 | |
Swabey89 | 31:087e295cc859 | 262 | buffer[newestIndex].updatetemp(temp_r); |
Swabey89 | 31:087e295cc859 | 263 | buffer[newestIndex].updatepress(press_r); |
Swabey89 | 31:087e295cc859 | 264 | buffer[newestIndex].updatelight(light_r); |
Swabey89 | 31:087e295cc859 | 265 | buffer[newestIndex].updateTime(); |
Swabey89 | 28:7fccaef8fa72 | 266 | |
Swabey89 | 28:7fccaef8fa72 | 267 | if (Nspaces != 0) |
Swabey89 | 28:7fccaef8fa72 | 268 | { |
Swabey89 | 28:7fccaef8fa72 | 269 | Nspaces--; |
Swabey89 | 28:7fccaef8fa72 | 270 | } |
Swabey89 | 28:7fccaef8fa72 | 271 | |
Swabey89 | 27:bb8d4c883e1b | 272 | samplesInBuffer.release(); |
Swabey89 | 27:bb8d4c883e1b | 273 | |
Swabey89 | 19:88d8359306a4 | 274 | //Pass onto queues |
Swabey89 | 31:087e295cc859 | 275 | //LCDqueue.call(LCD_display,temp_r,press_r,light_r); |
Swabey89 | 31:087e295cc859 | 276 | //LCDqueue.call(LCD_display, &buffer[newestIndex]); |
Swabey89 | 28:7fccaef8fa72 | 277 | |
Swabey89 | 28:7fccaef8fa72 | 278 | if(logging) |
Swabey89 | 28:7fccaef8fa72 | 279 | { |
Swabey89 | 31:087e295cc859 | 280 | /* |
Swabey89 | 28:7fccaef8fa72 | 281 | printlock.lock(); |
Swabey89 | 29:806e9281af2f | 282 | pc->printf("Sample placed in buffer at position %d\r\n", newestIndex); |
Swabey89 | 28:7fccaef8fa72 | 283 | pc->printf("Number of spaces available in buffer:%d\r\n\n",Nspaces); |
Swabey89 | 31:087e295cc859 | 284 | printlock.unlock(); |
Swabey89 | 31:087e295cc859 | 285 | */ |
Swabey89 | 31:087e295cc859 | 286 | printQueue.call(printf, "Sample placed in buffer at position %d\r\nNumber of spaces available in buffer:%d\r\n\n", newestIndex, Nspaces); |
Swabey89 | 28:7fccaef8fa72 | 287 | } |
Swabey89 | 28:7fccaef8fa72 | 288 | |
Swabey89 | 19:88d8359306a4 | 289 | bufferLock.unlock(); |
Swabey89 | 29:806e9281af2f | 290 | producer_tout.detach(); |
Swabey89 | 19:88d8359306a4 | 291 | } |
Swabey89 | 19:88d8359306a4 | 292 | } |
Swabey89 | 19:88d8359306a4 | 293 | |
Swabey89 | 19:88d8359306a4 | 294 | void sampleConsumer() |
Swabey89 | 19:88d8359306a4 | 295 | { |
Swabey89 | 19:88d8359306a4 | 296 | while(true) |
Swabey89 | 19:88d8359306a4 | 297 | { |
Swabey89 | 31:087e295cc859 | 298 | //static time_t seconds; //possibly move into if(sd_init) |
Swabey89 | 28:7fccaef8fa72 | 299 | //write to the SD card from oldestindex up to newestIndex. |
Swabey89 | 19:88d8359306a4 | 300 | |
Swabey89 | 28:7fccaef8fa72 | 301 | Nsamples = samplesInBuffer.wait(); //Block if no samples to take - acquires |
Swabey89 | 31:087e295cc859 | 302 | |
Swabey89 | 31:087e295cc859 | 303 | bufferLock.lock(); //Moved to here from below to try and ensure timer is started only when the buffer can be used |
Swabey89 | 30:7873beb54744 | 304 | consumer_tout.attach(consumer_toutISR,TOUT_TIME_DEF); |
Swabey89 | 19:88d8359306a4 | 305 | |
Swabey89 | 28:7fccaef8fa72 | 306 | if (sd_init) |
Swabey89 | 28:7fccaef8fa72 | 307 | { |
Swabey89 | 31:087e295cc859 | 308 | /* |
Swabey89 | 28:7fccaef8fa72 | 309 | char fileDate[30]; |
Swabey89 | 28:7fccaef8fa72 | 310 | timeLock.lock(); |
Swabey89 | 28:7fccaef8fa72 | 311 | seconds = time(NULL); |
Swabey89 | 28:7fccaef8fa72 | 312 | timeData = localtime(&seconds); |
Swabey89 | 28:7fccaef8fa72 | 313 | |
Swabey89 | 28:7fccaef8fa72 | 314 | //set_time(mktime(timeData)); |
Swabey89 | 28:7fccaef8fa72 | 315 | |
Swabey89 | 28:7fccaef8fa72 | 316 | strftime(fileDate, 30, "sd/log_%d_%m_%y.csv", timeData); |
Swabey89 | 31:087e295cc859 | 317 | timeLock.unlock(); |
Swabey89 | 28:7fccaef8fa72 | 318 | |
Swabey89 | 31:087e295cc859 | 319 | fp = fopen(fileDate,"a"); //ISSUE |
Swabey89 | 28:7fccaef8fa72 | 320 | if (fp == NULL) |
Swabey89 | 28:7fccaef8fa72 | 321 | { |
Swabey89 | 28:7fccaef8fa72 | 322 | printlock.lock(); |
Swabey89 | 31:087e295cc859 | 323 | pc->printf("WARNING: FILE COULD NOT BE OPENED\r\n\n"); |
Swabey89 | 28:7fccaef8fa72 | 324 | sd_init = false; |
Swabey89 | 28:7fccaef8fa72 | 325 | printlock.unlock(); |
Swabey89 | 28:7fccaef8fa72 | 326 | samplesInBuffer.release(); |
Swabey89 | 28:7fccaef8fa72 | 327 | } |
Swabey89 | 28:7fccaef8fa72 | 328 | else |
Swabey89 | 28:7fccaef8fa72 | 329 | { |
Swabey89 | 28:7fccaef8fa72 | 330 | //Nested locks probably a bad idea! |
Swabey89 | 31:087e295cc859 | 331 | //bufferLock.lock(); |
Swabey89 | 31:087e295cc859 | 332 | |
Swabey89 | 28:7fccaef8fa72 | 333 | SDlock.lock(); |
Swabey89 | 28:7fccaef8fa72 | 334 | oldestIndex = (oldestIndex+1) % BUFFERSIZE; |
Swabey89 | 31:087e295cc859 | 335 | //fprintf(fp,"%s,%5.2f,%5.2f,%5.2f\r", buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight()); |
Swabey89 | 31:087e295cc859 | 336 | SDqueue.call(SDaddSample,buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight()); |
Swabey89 | 28:7fccaef8fa72 | 337 | SDlock.unlock(); |
Swabey89 | 28:7fccaef8fa72 | 338 | |
Swabey89 | 28:7fccaef8fa72 | 339 | if(logging) |
Swabey89 | 28:7fccaef8fa72 | 340 | { |
Swabey89 | 28:7fccaef8fa72 | 341 | printlock.lock(); |
Swabey89 | 28:7fccaef8fa72 | 342 | pc->printf("Log file %s updated with sample from position %d in buffer\r\n",fileDate,oldestIndex); |
Swabey89 | 28:7fccaef8fa72 | 343 | pc->printf("newestIndex position %d\r\n",newestIndex); |
Swabey89 | 30:7873beb54744 | 344 | pc->printf("oldestIndex position %d\r\n\n",oldestIndex); |
Swabey89 | 28:7fccaef8fa72 | 345 | printlock.unlock(); |
Swabey89 | 28:7fccaef8fa72 | 346 | } |
Swabey89 | 28:7fccaef8fa72 | 347 | |
Swabey89 | 31:087e295cc859 | 348 | //bufferLock.unlock(); |
Swabey89 | 31:087e295cc859 | 349 | fclose(fp); |
Swabey89 | 31:087e295cc859 | 350 | */ |
Swabey89 | 31:087e295cc859 | 351 | oldestIndex = (oldestIndex+1) % BUFFERSIZE; |
Swabey89 | 31:087e295cc859 | 352 | //fprintf(fp,"%s,%5.2f,%5.2f,%5.2f\r", buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight()); |
Swabey89 | 31:087e295cc859 | 353 | SDqueue.call(SDaddSample,buffer[oldestIndex].getTime(), buffer[oldestIndex].gettemp(), buffer[oldestIndex].getpress(), buffer[oldestIndex].getlight(), oldestIndex); |
Swabey89 | 31:087e295cc859 | 354 | } |
Swabey89 | 23:f87fe0c55894 | 355 | else |
Swabey89 | 23:f87fe0c55894 | 356 | { |
Swabey89 | 28:7fccaef8fa72 | 357 | samplesInBuffer.release(); |
Swabey89 | 28:7fccaef8fa72 | 358 | } |
Swabey89 | 31:087e295cc859 | 359 | bufferLock.unlock(); |
Swabey89 | 29:806e9281af2f | 360 | consumer_tout.detach(); |
Swabey89 | 31:087e295cc859 | 361 | } |
Swabey89 | 31:087e295cc859 | 362 | |
Swabey89 | 19:88d8359306a4 | 363 | } |
Swabey89 | 24:81981815ef20 | 364 | |
Swabey89 | 24:81981815ef20 | 365 | //TEST FOR MOUNTING AND UNMOUNTING SD CARD |
Swabey89 | 24:81981815ef20 | 366 | //Interrupt service routine for handling the timeout |
Swabey89 | 24:81981815ef20 | 367 | |
Swabey89 | 24:81981815ef20 | 368 | |
Swabey89 | 24:81981815ef20 | 369 | void userswTimeOutHandler() { |
Swabey89 | 24:81981815ef20 | 370 | userswTimeOut.detach(); //Stop the timeout counter firing |
Swabey89 | 24:81981815ef20 | 371 | |
Swabey89 | 24:81981815ef20 | 372 | //Which event does this follow? |
Swabey89 | 24:81981815ef20 | 373 | switch (userswState) { |
Swabey89 | 24:81981815ef20 | 374 | case EDGE_RISEN: |
Swabey89 | 24:81981815ef20 | 375 | usersw.fall(&userswFallingEdge); //Now wait for a falling edge |
Swabey89 | 24:81981815ef20 | 376 | break; |
Swabey89 | 24:81981815ef20 | 377 | case EDGE_FALLEN: |
Swabey89 | 24:81981815ef20 | 378 | usersw.rise(&userswRisingEdge); //Now wait for a rising edge |
Swabey89 | 24:81981815ef20 | 379 | break; |
Swabey89 | 24:81981815ef20 | 380 | } //end switch |
Swabey89 | 24:81981815ef20 | 381 | } |
Swabey89 | 24:81981815ef20 | 382 | |
Swabey89 | 24:81981815ef20 | 383 | //Interrupt service routine for a rising edge (press) |
Swabey89 | 24:81981815ef20 | 384 | void userswRisingEdge() { |
Swabey89 | 24:81981815ef20 | 385 | usersw.rise(NULL); //Disable detecting more rising edges |
Swabey89 | 24:81981815ef20 | 386 | userswState = EDGE_RISEN; //Flag state |
Swabey89 | 24:81981815ef20 | 387 | userswTimeOut.attach(&userswTimeOutHandler, 0.2); //Start timeout timer |
Swabey89 | 24:81981815ef20 | 388 | } |
Swabey89 | 24:81981815ef20 | 389 | |
Swabey89 | 24:81981815ef20 | 390 | //Interrupt service routive for SW1 falling edge (release) |
Swabey89 | 24:81981815ef20 | 391 | void userswFallingEdge() { |
Swabey89 | 24:81981815ef20 | 392 | usersw.fall(NULL); //Disable this interrupt |
Swabey89 | 31:087e295cc859 | 393 | //SDmount_thread.signal_set(SIGNAL_SD); |
Swabey89 | 31:087e295cc859 | 394 | SDqueue.call(SDmount); |
Swabey89 | 24:81981815ef20 | 395 | userswState = EDGE_FALLEN; //Flag state |
Swabey89 | 24:81981815ef20 | 396 | userswTimeOut.attach(&userswTimeOutHandler, 0.2); //Start timeout counter - may want to increase this |
Swabey89 | 24:81981815ef20 | 397 | } |
Swabey89 | 29:806e9281af2f | 398 | |
Swabey89 | 29:806e9281af2f | 399 | //TEST FOR WATCHDOG |
Swabey89 | 29:806e9281af2f | 400 | |
Swabey89 | 29:806e9281af2f | 401 | //ISR |
Swabey89 | 29:806e9281af2f | 402 | void producer_toutISR(void) |
Swabey89 | 29:806e9281af2f | 403 | { |
Swabey89 | 29:806e9281af2f | 404 | threadstates |= PRODUCER; |
Swabey89 | 29:806e9281af2f | 405 | } |
Swabey89 | 29:806e9281af2f | 406 | |
Swabey89 | 29:806e9281af2f | 407 | void consumer_toutISR(void) |
Swabey89 | 29:806e9281af2f | 408 | { |
Swabey89 | 29:806e9281af2f | 409 | threadstates |= CONSUMER; |
Swabey89 | 29:806e9281af2f | 410 | } |
Swabey89 | 29:806e9281af2f | 411 | |
Swabey89 | 29:806e9281af2f | 412 | void serial_toutISR(void) |
Swabey89 | 29:806e9281af2f | 413 | { |
Swabey89 | 29:806e9281af2f | 414 | threadstates |= SERIAL; |
Swabey89 | 29:806e9281af2f | 415 | } |
Swabey89 | 29:806e9281af2f | 416 | |
Swabey89 | 29:806e9281af2f | 417 | void SD_toutISR(void) |
Swabey89 | 29:806e9281af2f | 418 | { |
Swabey89 | 29:806e9281af2f | 419 | threadstates |= SD; |
Swabey89 | 29:806e9281af2f | 420 | } |
Swabey89 | 29:806e9281af2f | 421 | |
Swabey89 | 29:806e9281af2f | 422 | void LCD_toutISR(void) |
Swabey89 | 29:806e9281af2f | 423 | { |
Swabey89 | 29:806e9281af2f | 424 | threadstates |= LCD; |
Swabey89 | 29:806e9281af2f | 425 | } |
Swabey89 | 29:806e9281af2f | 426 | |
Swabey89 | 29:806e9281af2f | 427 | void network_toutISR(void) |
Swabey89 | 29:806e9281af2f | 428 | { |
Swabey89 | 29:806e9281af2f | 429 | threadstates |= NETWORK; |
Swabey89 | 29:806e9281af2f | 430 | } |
Swabey89 | 29:806e9281af2f | 431 | |
Swabey89 | 29:806e9281af2f | 432 | void watchdog(void) |
Swabey89 | 29:806e9281af2f | 433 | { |
Swabey89 | 29:806e9281af2f | 434 | while(true) |
Swabey89 | 29:806e9281af2f | 435 | { |
Swabey89 | 29:806e9281af2f | 436 | Thread::wait(10000); |
Swabey89 | 29:806e9281af2f | 437 | |
Swabey89 | 29:806e9281af2f | 438 | if(threadstates) |
Swabey89 | 29:806e9281af2f | 439 | { |
Swabey89 | 29:806e9281af2f | 440 | producer_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 441 | consumer_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 442 | serial_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 443 | SDqueue_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 444 | LCDqueue_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 445 | network_thread.terminate(); |
Swabey89 | 31:087e295cc859 | 446 | printf_thread.terminate(); |
Swabey89 | 29:806e9281af2f | 447 | |
Swabey89 | 29:806e9281af2f | 448 | pc->printf("THREAD PSW: 0x%x\n\r", threadstates); |
Swabey89 | 29:806e9281af2f | 449 | |
Swabey89 | 29:806e9281af2f | 450 | switch (threadstates) |
Swabey89 | 29:806e9281af2f | 451 | { |
Swabey89 | 29:806e9281af2f | 452 | case (PRODUCER) : |
Swabey89 | 29:806e9281af2f | 453 | pc->printf("PRODUCER THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 454 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 455 | lcd.printf("PRODUCER\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 456 | break; |
Swabey89 | 29:806e9281af2f | 457 | |
Swabey89 | 29:806e9281af2f | 458 | case (CONSUMER) : |
Swabey89 | 29:806e9281af2f | 459 | pc->printf("CONSUMER THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 460 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 461 | lcd.printf("CONSUMER\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 462 | break; |
Swabey89 | 29:806e9281af2f | 463 | |
Swabey89 | 29:806e9281af2f | 464 | case (SERIAL) : |
Swabey89 | 29:806e9281af2f | 465 | pc->printf("SERIAL THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 466 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 467 | lcd.printf("SERIAL\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 468 | break; |
Swabey89 | 29:806e9281af2f | 469 | |
Swabey89 | 29:806e9281af2f | 470 | case (SD) : |
Swabey89 | 29:806e9281af2f | 471 | pc->printf("SD CARD THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 472 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 473 | lcd.printf("SD CARD\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 474 | break; |
Swabey89 | 29:806e9281af2f | 475 | |
Swabey89 | 29:806e9281af2f | 476 | case (LCD) : |
Swabey89 | 29:806e9281af2f | 477 | pc->printf("LCD THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 478 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 479 | lcd.printf("LCD\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 480 | break; |
Swabey89 | 29:806e9281af2f | 481 | |
Swabey89 | 29:806e9281af2f | 482 | case (NETWORK) : |
Swabey89 | 29:806e9281af2f | 483 | pc->printf("NETWORK THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 484 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 485 | lcd.printf("NETWORK\nDEADLOCK"); |
Swabey89 | 29:806e9281af2f | 486 | break; |
Swabey89 | 29:806e9281af2f | 487 | |
Swabey89 | 29:806e9281af2f | 488 | default: |
Swabey89 | 29:806e9281af2f | 489 | pc->printf("MULTIPLE THREAD DEADLOCK\r\n\n"); |
Swabey89 | 29:806e9281af2f | 490 | lcd.cls(); |
Swabey89 | 29:806e9281af2f | 491 | lcd.printf("DEADLOCK"); |
Swabey89 | 29:806e9281af2f | 492 | break; |
Swabey89 | 29:806e9281af2f | 493 | } |
Swabey89 | 29:806e9281af2f | 494 | |
Swabey89 | 29:806e9281af2f | 495 | for (int i = 0;i<50;i++) |
Swabey89 | 29:806e9281af2f | 496 | { |
Swabey89 | 29:806e9281af2f | 497 | redLED = 1; |
Swabey89 | 29:806e9281af2f | 498 | wait(0.05); |
Swabey89 | 29:806e9281af2f | 499 | redLED = 0; |
Swabey89 | 29:806e9281af2f | 500 | wait(0.05); |
Swabey89 | 29:806e9281af2f | 501 | } |
Swabey89 | 29:806e9281af2f | 502 | NVIC_SystemReset(); |
Swabey89 | 29:806e9281af2f | 503 | } |
Swabey89 | 31:087e295cc859 | 504 | else if (logging) |
Swabey89 | 31:087e295cc859 | 505 | { |
Swabey89 | 31:087e295cc859 | 506 | /* |
Swabey89 | 31:087e295cc859 | 507 | printlock.lock(); |
Swabey89 | 31:087e295cc859 | 508 | pc->printf("WATCHDOG RAN WITH NO DEADLOCKED THREADS\r\n\n"); |
Swabey89 | 31:087e295cc859 | 509 | printlock.unlock(); |
Swabey89 | 31:087e295cc859 | 510 | */ |
Swabey89 | 31:087e295cc859 | 511 | printQueue.call(printf,"WATCHDOG RAN WITH NO DEADLOCKED THREADS\r\n\n"); |
Swabey89 | 31:087e295cc859 | 512 | } |
Swabey89 | 29:806e9281af2f | 513 | } |
Swabey89 | 31:087e295cc859 | 514 | } |
Swabey89 | 31:087e295cc859 | 515 | |
Swabey89 | 31:087e295cc859 | 516 | void PLL_Config(void) |
Swabey89 | 31:087e295cc859 | 517 | { |
Swabey89 | 31:087e295cc859 | 518 | |
Swabey89 | 31:087e295cc859 | 519 | |
Swabey89 | 31:087e295cc859 | 520 | //******************************************************************************* |
Swabey89 | 31:087e295cc859 | 521 | //* PLL (clocked by HSI) used as System clock source * |
Swabey89 | 31:087e295cc859 | 522 | //* By Stuart MacVeigh * |
Swabey89 | 31:087e295cc859 | 523 | //******************************************************************************* |
Swabey89 | 31:087e295cc859 | 524 | |
Swabey89 | 31:087e295cc859 | 525 | RCC->APB1ENR |= RCC_APB1ENR_PWREN; //enable power interface clock source |
Swabey89 | 31:087e295cc859 | 526 | PWR->CR |= PWR_CR_VOS; |
Swabey89 | 31:087e295cc859 | 527 | |
Swabey89 | 31:087e295cc859 | 528 | |
Swabey89 | 31:087e295cc859 | 529 | #define PLL_N 180 //SYSTEM CLOCK SPEED (FCY (MHz)) |
Swabey89 | 31:087e295cc859 | 530 | #define HSI 16000000 //INTERAL OSC FREQUENCY |
Swabey89 | 31:087e295cc859 | 531 | |
Swabey89 | 31:087e295cc859 | 532 | #define PLL_M (HSI/2000000) //Fcy = Fxtal x PLL_N/(PLL_P x PLL_M) |
Swabey89 | 31:087e295cc859 | 533 | #define PLL_P 2 |
Swabey89 | 31:087e295cc859 | 534 | #define PLL_Q 7 |
Swabey89 | 31:087e295cc859 | 535 | // HCLK = SYSCLK / 1 |
Swabey89 | 31:087e295cc859 | 536 | RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //CORE CLOCK = 180MHZ |
Swabey89 | 31:087e295cc859 | 537 | |
Swabey89 | 31:087e295cc859 | 538 | // PCLK2 = HCLK / 2 |
Swabey89 | 31:087e295cc859 | 539 | RCC->CFGR |= RCC_CFGR_PPRE2_DIV4; //PERIPHERAL CLOCK 2 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ |
Swabey89 | 31:087e295cc859 | 540 | |
Swabey89 | 31:087e295cc859 | 541 | // PCLK1 = HCLK / 4 |
Swabey89 | 31:087e295cc859 | 542 | RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //PERIPHERAL CLOCK 1 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ |
Swabey89 | 31:087e295cc859 | 543 | |
Swabey89 | 31:087e295cc859 | 544 | // Configure the main PLL |
Swabey89 | 31:087e295cc859 | 545 | RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24); |
Swabey89 | 31:087e295cc859 | 546 | |
Swabey89 | 31:087e295cc859 | 547 | // Enable the main PLL |
Swabey89 | 31:087e295cc859 | 548 | RCC->CR |= RCC_CR_PLLON; |
Swabey89 | 31:087e295cc859 | 549 | |
Swabey89 | 31:087e295cc859 | 550 | // Wait till the main PLL is ready |
Swabey89 | 31:087e295cc859 | 551 | while(!(RCC->CR & RCC_CR_PLLRDY)); |
Swabey89 | 31:087e295cc859 | 552 | |
Swabey89 | 31:087e295cc859 | 553 | // Configure Flash prefetch, Instruction cache, Data cache and wait state |
Swabey89 | 31:087e295cc859 | 554 | FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; |
Swabey89 | 31:087e295cc859 | 555 | |
Swabey89 | 31:087e295cc859 | 556 | // Select the main PLL as system clock source |
Swabey89 | 31:087e295cc859 | 557 | RCC->CFGR &=~ RCC_CFGR_SW; |
Swabey89 | 31:087e295cc859 | 558 | RCC->CFGR |= RCC_CFGR_SW_PLL; |
Swabey89 | 31:087e295cc859 | 559 | |
Swabey89 | 31:087e295cc859 | 560 | // Wait till the main PLL is used as system clock source |
Swabey89 | 31:087e295cc859 | 561 | while ((RCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); |
Swabey89 | 31:087e295cc859 | 562 | |
Swabey89 | 31:087e295cc859 | 563 | //****************************************************************************** |
Swabey89 | 31:087e295cc859 | 564 | //* END PLL (CLOCKED BY HSI) SETUP CODE * |
Swabey89 | 31:087e295cc859 | 565 | //****************************************************************************** |
Swabey89 | 31:087e295cc859 | 566 | |
Swabey89 | 29:806e9281af2f | 567 | } |