mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
bogdanm
Date:
Wed Aug 07 16:43:59 2013 +0300
Revision:
15:4892fe388435
Parent:
13:0645d8841f51
Child:
72:248c61396e08
Added LPC4088 target and interrupt chaining code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bogdanm 15:4892fe388435 1 /* mbed Microcontroller Library
bogdanm 15:4892fe388435 2 * Copyright (c) 2006-2013 ARM Limited
bogdanm 15:4892fe388435 3 *
bogdanm 15:4892fe388435 4 * Licensed under the Apache License, Version 2.0 (the "License");
bogdanm 15:4892fe388435 5 * you may not use this file except in compliance with the License.
bogdanm 15:4892fe388435 6 * You may obtain a copy of the License at
bogdanm 15:4892fe388435 7 *
bogdanm 15:4892fe388435 8 * http://www.apache.org/licenses/LICENSE-2.0
bogdanm 15:4892fe388435 9 *
bogdanm 15:4892fe388435 10 * Unless required by applicable law or agreed to in writing, software
bogdanm 15:4892fe388435 11 * distributed under the License is distributed on an "AS IS" BASIS,
bogdanm 15:4892fe388435 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
bogdanm 15:4892fe388435 13 * See the License for the specific language governing permissions and
bogdanm 15:4892fe388435 14 * limitations under the License.
bogdanm 15:4892fe388435 15 */
bogdanm 15:4892fe388435 16 #include "serial_api.h"
bogdanm 15:4892fe388435 17
bogdanm 15:4892fe388435 18 // math.h required for floating point operations for baud rate calculation
bogdanm 15:4892fe388435 19 #include <math.h>
bogdanm 15:4892fe388435 20
bogdanm 15:4892fe388435 21 #include <string.h>
bogdanm 15:4892fe388435 22
bogdanm 15:4892fe388435 23 #include "cmsis.h"
bogdanm 15:4892fe388435 24 #include "pinmap.h"
bogdanm 15:4892fe388435 25 #include "error.h"
bogdanm 15:4892fe388435 26
bogdanm 15:4892fe388435 27 /******************************************************************************
bogdanm 15:4892fe388435 28 * INITIALIZATION
bogdanm 15:4892fe388435 29 ******************************************************************************/
bogdanm 15:4892fe388435 30 static const PinMap PinMap_UART_TX[] = {
bogdanm 15:4892fe388435 31 {PTC4, UART_1, 3},
bogdanm 15:4892fe388435 32 {PTA2, UART_0, 2},
bogdanm 15:4892fe388435 33 {PTD5, UART_2, 3},
bogdanm 15:4892fe388435 34 {PTD3, UART_2, 3},
bogdanm 15:4892fe388435 35 {PTD7, UART_0, 3},
bogdanm 15:4892fe388435 36 {PTE20, UART_0, 4},
bogdanm 15:4892fe388435 37 {PTE22, UART_2, 4},
bogdanm 15:4892fe388435 38 {PTE0, UART_1, 3},
bogdanm 15:4892fe388435 39 {NC , NC , 0}
bogdanm 15:4892fe388435 40 };
bogdanm 15:4892fe388435 41
bogdanm 15:4892fe388435 42 static const PinMap PinMap_UART_RX[] = {
bogdanm 15:4892fe388435 43 {PTC3, UART_1, 3},
bogdanm 15:4892fe388435 44 {PTA1, UART_0, 2},
bogdanm 15:4892fe388435 45 {PTD4, UART_2, 3},
bogdanm 15:4892fe388435 46 {PTD2, UART_2, 3},
bogdanm 15:4892fe388435 47 {PTD6, UART_0, 3},
bogdanm 15:4892fe388435 48 {PTE23, UART_2, 4},
bogdanm 15:4892fe388435 49 {PTE21, UART_0, 4},
bogdanm 15:4892fe388435 50 {PTE1, UART_1, 3},
bogdanm 15:4892fe388435 51 {NC , NC , 0}
bogdanm 15:4892fe388435 52 };
bogdanm 15:4892fe388435 53
bogdanm 15:4892fe388435 54 #define UART_NUM 3
bogdanm 15:4892fe388435 55 static uint32_t serial_irq_ids[UART_NUM] = {0};
bogdanm 15:4892fe388435 56 static uart_irq_handler irq_handler;
bogdanm 15:4892fe388435 57
bogdanm 15:4892fe388435 58 int stdio_uart_inited = 0;
bogdanm 15:4892fe388435 59 serial_t stdio_uart;
bogdanm 15:4892fe388435 60
bogdanm 15:4892fe388435 61 void serial_init(serial_t *obj, PinName tx, PinName rx) {
bogdanm 15:4892fe388435 62 // determine the UART to use
bogdanm 15:4892fe388435 63 UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
bogdanm 15:4892fe388435 64 UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
bogdanm 15:4892fe388435 65 UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
bogdanm 15:4892fe388435 66 if ((int)uart == NC) {
bogdanm 15:4892fe388435 67 error("Serial pinout mapping failed");
bogdanm 15:4892fe388435 68 }
bogdanm 15:4892fe388435 69
bogdanm 15:4892fe388435 70 obj->uart = (UARTLP_Type *)uart;
bogdanm 15:4892fe388435 71 // enable clk
bogdanm 15:4892fe388435 72 switch (uart) {
bogdanm 15:4892fe388435 73 case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT);
bogdanm 15:4892fe388435 74 SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
bogdanm 15:4892fe388435 75 case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
bogdanm 15:4892fe388435 76 case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
bogdanm 15:4892fe388435 77 }
bogdanm 15:4892fe388435 78 // Disable UART before changing registers
bogdanm 13:0645d8841f51 79 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 13:0645d8841f51 80
bogdanm 13:0645d8841f51 81 switch (uart) {
bogdanm 13:0645d8841f51 82 case UART_0: obj->index = 0; break;
bogdanm 13:0645d8841f51 83 case UART_1: obj->index = 1; break;
bogdanm 13:0645d8841f51 84 case UART_2: obj->index = 2; break;
bogdanm 15:4892fe388435 85 }
bogdanm 15:4892fe388435 86
bogdanm 15:4892fe388435 87 // set default baud rate and format
bogdanm 15:4892fe388435 88 serial_baud (obj, 9600);
bogdanm 15:4892fe388435 89 serial_format(obj, 8, ParityNone, 1);
bogdanm 15:4892fe388435 90
bogdanm 15:4892fe388435 91 // pinout the chosen uart
bogdanm 15:4892fe388435 92 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 15:4892fe388435 93 pinmap_pinout(rx, PinMap_UART_RX);
bogdanm 15:4892fe388435 94
bogdanm 15:4892fe388435 95 // set rx/tx pins in PullUp mode
bogdanm 15:4892fe388435 96 pin_mode(tx, PullUp);
bogdanm 15:4892fe388435 97 pin_mode(rx, PullUp);
bogdanm 15:4892fe388435 98
bogdanm 15:4892fe388435 99 obj->uart->C2 |= (UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 15:4892fe388435 100
bogdanm 15:4892fe388435 101 if (uart == STDIO_UART) {
bogdanm 15:4892fe388435 102 stdio_uart_inited = 1;
bogdanm 15:4892fe388435 103 memcpy(&stdio_uart, obj, sizeof(serial_t));
bogdanm 15:4892fe388435 104 }
bogdanm 15:4892fe388435 105 }
bogdanm 15:4892fe388435 106
bogdanm 15:4892fe388435 107 void serial_free(serial_t *obj) {
bogdanm 15:4892fe388435 108 serial_irq_ids[obj->index] = 0;
bogdanm 15:4892fe388435 109 }
bogdanm 15:4892fe388435 110
bogdanm 15:4892fe388435 111 // serial_baud
bogdanm 15:4892fe388435 112 //
bogdanm 15:4892fe388435 113 // set the baud rate, taking in to account the current SystemFrequency
bogdanm 15:4892fe388435 114 //
bogdanm 15:4892fe388435 115 // The LPC2300 and LPC1700 have a divider and a fractional divider to control the
bogdanm 15:4892fe388435 116 // baud rate. The formula is:
bogdanm 15:4892fe388435 117 //
bogdanm 15:4892fe388435 118 // Baudrate = (1 / PCLK) * 16 * DL * (1 + DivAddVal / MulVal)
bogdanm 15:4892fe388435 119 // where:
bogdanm 15:4892fe388435 120 // 1 < MulVal <= 15
bogdanm 15:4892fe388435 121 // 0 <= DivAddVal < 14
bogdanm 15:4892fe388435 122 // DivAddVal < MulVal
bogdanm 15:4892fe388435 123 //
bogdanm 15:4892fe388435 124 void serial_baud(serial_t *obj, int baudrate) {
bogdanm 15:4892fe388435 125
bogdanm 15:4892fe388435 126 // save C2 state
bogdanm 15:4892fe388435 127 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
bogdanm 15:4892fe388435 128
bogdanm 15:4892fe388435 129 // Disable UART before changing registers
bogdanm 15:4892fe388435 130 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 15:4892fe388435 131
bogdanm 15:4892fe388435 132 // [TODO] not hardcode this value
bogdanm 15:4892fe388435 133 uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
bogdanm 15:4892fe388435 134
bogdanm 15:4892fe388435 135 // First we check to see if the basic divide with no DivAddVal/MulVal
bogdanm 15:4892fe388435 136 // ratio gives us an integer result. If it does, we set DivAddVal = 0,
bogdanm 15:4892fe388435 137 // MulVal = 1. Otherwise, we search the valid ratio value range to find
bogdanm 15:4892fe388435 138 // the closest match. This could be more elegant, using search methods
bogdanm 15:4892fe388435 139 // and/or lookup tables, but the brute force method is not that much
bogdanm 15:4892fe388435 140 // slower, and is more maintainable.
bogdanm 15:4892fe388435 141 uint16_t DL = PCLK / (16 * baudrate);
bogdanm 15:4892fe388435 142
bogdanm 15:4892fe388435 143 // set BDH and BDL
bogdanm 15:4892fe388435 144 obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
bogdanm 15:4892fe388435 145 obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
bogdanm 15:4892fe388435 146
bogdanm 15:4892fe388435 147 // restore C2 state
bogdanm 15:4892fe388435 148 obj->uart->C2 |= c2_state;
bogdanm 15:4892fe388435 149 }
bogdanm 15:4892fe388435 150
bogdanm 15:4892fe388435 151 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
bogdanm 13:0645d8841f51 152 uint8_t m10 = 0;
bogdanm 15:4892fe388435 153
bogdanm 15:4892fe388435 154 // save C2 state
bogdanm 15:4892fe388435 155 uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
bogdanm 15:4892fe388435 156
bogdanm 15:4892fe388435 157 // Disable UART before changing registers
bogdanm 15:4892fe388435 158 obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
bogdanm 15:4892fe388435 159
bogdanm 15:4892fe388435 160 // 8 data bits = 0 ... 9 data bits = 1
bogdanm 15:4892fe388435 161 if ((data_bits < 8) || (data_bits > 9)) {
bogdanm 15:4892fe388435 162 error("Invalid number of bits (%d) in serial format, should be 8..9\r\n", data_bits);
bogdanm 13:0645d8841f51 163 }
bogdanm 15:4892fe388435 164 data_bits -= 8;
bogdanm 15:4892fe388435 165
bogdanm 15:4892fe388435 166 uint8_t parity_enable, parity_select;
bogdanm 15:4892fe388435 167 switch (parity) {
bogdanm 15:4892fe388435 168 case ParityNone: parity_enable = 0; parity_select = 0; break;
bogdanm 15:4892fe388435 169 case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break;
bogdanm 15:4892fe388435 170 case ParityEven: parity_enable = 1; parity_select = 0; data_bits++; break;
bogdanm 15:4892fe388435 171 default:
bogdanm 15:4892fe388435 172 error("Invalid serial parity setting\r\n");
bogdanm 15:4892fe388435 173 return;
bogdanm 15:4892fe388435 174 }
bogdanm 15:4892fe388435 175
bogdanm 15:4892fe388435 176 // 1 stop bits = 0, 2 stop bits = 1
bogdanm 15:4892fe388435 177 if ((stop_bits != 1) && (stop_bits != 2)) {
bogdanm 15:4892fe388435 178 error("Invalid stop bits specified\r\n");
bogdanm 15:4892fe388435 179 }
bogdanm 13:0645d8841f51 180 stop_bits -= 1;
bogdanm 13:0645d8841f51 181
bogdanm 13:0645d8841f51 182 // 9 data bits + parity
bogdanm 13:0645d8841f51 183 if (data_bits == 2) {
bogdanm 13:0645d8841f51 184 // only uart0 supports 10 bit communication
bogdanm 13:0645d8841f51 185 if (obj->index != 0) {
bogdanm 13:0645d8841f51 186 error("Invalid number of bits (9) to be used with parity\r\n");
bogdanm 13:0645d8841f51 187 }
bogdanm 13:0645d8841f51 188 data_bits = 0;
bogdanm 13:0645d8841f51 189 m10 = 1;
bogdanm 15:4892fe388435 190 }
bogdanm 15:4892fe388435 191
bogdanm 15:4892fe388435 192 // data bits, parity and parity mode
bogdanm 15:4892fe388435 193 obj->uart->C1 = ((data_bits << 4)
bogdanm 15:4892fe388435 194 | (parity_enable << 1)
bogdanm 13:0645d8841f51 195 | (parity_select << 0));
bogdanm 13:0645d8841f51 196
bogdanm 13:0645d8841f51 197 // enable 10bit mode if needed
bogdanm 13:0645d8841f51 198 if (obj->index == 0) {
bogdanm 13:0645d8841f51 199 obj->uart->C4 &= ~UARTLP_C4_M10_MASK;
bogdanm 13:0645d8841f51 200 obj->uart->C4 |= (m10 << UARTLP_C4_M10_SHIFT);
bogdanm 13:0645d8841f51 201 }
bogdanm 15:4892fe388435 202
bogdanm 15:4892fe388435 203 // stop bits
bogdanm 15:4892fe388435 204 obj->uart->BDH &= ~UART_BDH_SBNS_MASK;
bogdanm 15:4892fe388435 205 obj->uart->BDH |= (stop_bits << UART_BDH_SBNS_SHIFT);
bogdanm 15:4892fe388435 206
bogdanm 15:4892fe388435 207 // restore C2 state
bogdanm 15:4892fe388435 208 obj->uart->C2 |= c2_state;
bogdanm 15:4892fe388435 209 }
bogdanm 15:4892fe388435 210
bogdanm 15:4892fe388435 211 /******************************************************************************
bogdanm 15:4892fe388435 212 * INTERRUPTS HANDLING
bogdanm 15:4892fe388435 213 ******************************************************************************/
bogdanm 15:4892fe388435 214 static inline void uart_irq(uint8_t status, uint32_t index) {
bogdanm 15:4892fe388435 215 if (serial_irq_ids[index] != 0) {
bogdanm 15:4892fe388435 216 if (status & UART_S1_TDRE_MASK)
bogdanm 15:4892fe388435 217 irq_handler(serial_irq_ids[index], TxIrq);
bogdanm 15:4892fe388435 218
bogdanm 15:4892fe388435 219 if (status & UART_S1_RDRF_MASK)
bogdanm 15:4892fe388435 220 irq_handler(serial_irq_ids[index], RxIrq);
bogdanm 15:4892fe388435 221 }
bogdanm 15:4892fe388435 222 }
bogdanm 15:4892fe388435 223
bogdanm 15:4892fe388435 224 void uart0_irq() {
bogdanm 15:4892fe388435 225 uart_irq(UART0->S1, 0);
bogdanm 15:4892fe388435 226 if (UART0->S1 & UART_S1_OR_MASK)
bogdanm 15:4892fe388435 227 UART0->S1 |= UART_S1_OR_MASK;
bogdanm 15:4892fe388435 228 }
bogdanm 15:4892fe388435 229 void uart1_irq() {uart_irq(UART1->S1, 1);}
bogdanm 15:4892fe388435 230 void uart2_irq() {uart_irq(UART2->S1, 2);}
bogdanm 15:4892fe388435 231
bogdanm 15:4892fe388435 232 void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
bogdanm 15:4892fe388435 233 irq_handler = handler;
bogdanm 15:4892fe388435 234 serial_irq_ids[obj->index] = id;
bogdanm 15:4892fe388435 235 }
bogdanm 15:4892fe388435 236
bogdanm 15:4892fe388435 237 void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
bogdanm 15:4892fe388435 238 IRQn_Type irq_n = (IRQn_Type)0;
bogdanm 15:4892fe388435 239 uint32_t vector = 0;
bogdanm 15:4892fe388435 240 switch ((int)obj->uart) {
bogdanm 15:4892fe388435 241 case UART_0: irq_n=UART0_IRQn; vector = (uint32_t)&uart0_irq; break;
bogdanm 15:4892fe388435 242 case UART_1: irq_n=UART1_IRQn; vector = (uint32_t)&uart1_irq; break;
bogdanm 15:4892fe388435 243 case UART_2: irq_n=UART2_IRQn; vector = (uint32_t)&uart2_irq; break;
bogdanm 15:4892fe388435 244 }
bogdanm 15:4892fe388435 245
bogdanm 15:4892fe388435 246 if (enable) {
bogdanm 15:4892fe388435 247 switch (irq) {
bogdanm 15:4892fe388435 248 case RxIrq: obj->uart->C2 |= (UART_C2_RIE_MASK); break;
bogdanm 15:4892fe388435 249 case TxIrq: obj->uart->C2 |= (UART_C2_TIE_MASK); break;
bogdanm 15:4892fe388435 250 }
bogdanm 15:4892fe388435 251 NVIC_SetVector(irq_n, vector);
bogdanm 15:4892fe388435 252 NVIC_EnableIRQ(irq_n);
bogdanm 15:4892fe388435 253
bogdanm 15:4892fe388435 254 } else { // disable
bogdanm 15:4892fe388435 255 int all_disabled = 0;
bogdanm 15:4892fe388435 256 SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
bogdanm 15:4892fe388435 257 switch (irq) {
bogdanm 15:4892fe388435 258 case RxIrq: obj->uart->C2 &= ~(UART_C2_RIE_MASK); break;
bogdanm 15:4892fe388435 259 case TxIrq: obj->uart->C2 &= ~(UART_C2_TIE_MASK); break;
bogdanm 15:4892fe388435 260 }
bogdanm 15:4892fe388435 261 switch (other_irq) {
bogdanm 15:4892fe388435 262 case RxIrq: all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0; break;
bogdanm 15:4892fe388435 263 case TxIrq: all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0; break;
bogdanm 15:4892fe388435 264 }
bogdanm 15:4892fe388435 265 if (all_disabled)
bogdanm 15:4892fe388435 266 NVIC_DisableIRQ(irq_n);
bogdanm 15:4892fe388435 267 }
bogdanm 15:4892fe388435 268 }
bogdanm 15:4892fe388435 269
bogdanm 15:4892fe388435 270 /******************************************************************************
bogdanm 15:4892fe388435 271 * READ/WRITE
bogdanm 15:4892fe388435 272 ******************************************************************************/
bogdanm 15:4892fe388435 273 int serial_getc(serial_t *obj) {
bogdanm 15:4892fe388435 274 while (!serial_readable(obj));
bogdanm 15:4892fe388435 275 return obj->uart->D;
bogdanm 15:4892fe388435 276 }
bogdanm 15:4892fe388435 277
bogdanm 15:4892fe388435 278 void serial_putc(serial_t *obj, int c) {
bogdanm 15:4892fe388435 279 while (!serial_writable(obj));
bogdanm 15:4892fe388435 280 obj->uart->D = c;
bogdanm 15:4892fe388435 281 }
bogdanm 15:4892fe388435 282
bogdanm 15:4892fe388435 283 int serial_readable(serial_t *obj) {
bogdanm 15:4892fe388435 284 // check overrun
bogdanm 15:4892fe388435 285 if (obj->uart->S1 & UART_S1_OR_MASK) {
bogdanm 15:4892fe388435 286 obj->uart->S1 |= UART_S1_OR_MASK;
bogdanm 15:4892fe388435 287 }
bogdanm 15:4892fe388435 288 return (obj->uart->S1 & UART_S1_RDRF_MASK);
bogdanm 15:4892fe388435 289 }
bogdanm 15:4892fe388435 290
bogdanm 15:4892fe388435 291 int serial_writable(serial_t *obj) {
bogdanm 15:4892fe388435 292 // check overrun
bogdanm 15:4892fe388435 293 if (obj->uart->S1 & UART_S1_OR_MASK) {
bogdanm 15:4892fe388435 294 obj->uart->S1 |= UART_S1_OR_MASK;
bogdanm 15:4892fe388435 295 }
bogdanm 15:4892fe388435 296 return (obj->uart->S1 & UART_S1_TDRE_MASK);
bogdanm 15:4892fe388435 297 }
bogdanm 15:4892fe388435 298
bogdanm 15:4892fe388435 299 void serial_clear(serial_t *obj) {
bogdanm 15:4892fe388435 300 }
bogdanm 15:4892fe388435 301
bogdanm 15:4892fe388435 302 void serial_pinout_tx(PinName tx) {
bogdanm 15:4892fe388435 303 pinmap_pinout(tx, PinMap_UART_TX);
bogdanm 15:4892fe388435 304 }
bogdanm 15:4892fe388435 305
bogdanm 15:4892fe388435 306 void serial_break_set(serial_t *obj) {
bogdanm 15:4892fe388435 307 obj->uart->C2 |= UART_C2_SBK_MASK;
bogdanm 15:4892fe388435 308 }
bogdanm 15:4892fe388435 309
bogdanm 15:4892fe388435 310 void serial_break_clear(serial_t *obj) {
bogdanm 15:4892fe388435 311 obj->uart->C2 &= ~UART_C2_SBK_MASK;
bogdanm 15:4892fe388435 312 }
bogdanm 15:4892fe388435 313