1 /* 2 * COPYRIGHT (C) 2006-2018, RT-Thread Development Team 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 25 * OF SUCH DAMAGE. 26 * 27 * Change Logs: 28 * Date Author Notes 29 * 2012-12-8 Bernard add file header 30 * export bsd socket symbol for RT-Thread Application Module 31 * 2017-11-15 Bernard add lock for init_done callback. 32 */ 33 34 #include <rtthread.h> 35 36 #include "lwip/sys.h" 37 #include "lwip/opt.h" 38 #include "lwip/stats.h" 39 #include "lwip/err.h" 40 #include "arch/sys_arch.h" 41 #include "lwip/debug.h" 42 #include "lwip/netif.h" 43 #include "lwip/tcpip.h" 44 #include "netif/ethernetif.h" 45 #include "lwip/sio.h" 46 #include <lwip/init.h> 47 #include "lwip/inet.h" 48 49 #include <string.h> 50 51 /* 52 * Initialize the network interface device 53 * 54 * @return the operation status, ERR_OK on OK, ERR_IF on error 55 */ 56 static err_t netif_device_init(struct netif *netif) 57 { 58 struct eth_device *ethif; 59 60 ethif = (struct eth_device *)netif->state; 61 if (ethif != RT_NULL) 62 { 63 rt_device_t device; 64 65 /* get device object */ 66 device = (rt_device_t) ethif; 67 if (rt_device_init(device) != RT_EOK) 68 { 69 return ERR_IF; 70 } 71 72 /* copy device flags to netif flags */ 73 netif->flags = ethif->flags; 74 75 return ERR_OK; 76 } 77 78 return ERR_IF; 79 } 80 /* 81 * Initialize the ethernetif layer and set network interface device up 82 */ 83 static void tcpip_init_done_callback(void *arg) 84 { 85 rt_device_t device; 86 struct eth_device *ethif; 87 struct ip_addr ipaddr, netmask, gw; 88 struct rt_list_node* node; 89 struct rt_object* object; 90 struct rt_object_information *information; 91 92 LWIP_ASSERT("invalid arg.\n",arg); 93 94 IP4_ADDR(&gw, 0,0,0,0); 95 IP4_ADDR(&ipaddr, 0,0,0,0); 96 IP4_ADDR(&netmask, 0,0,0,0); 97 98 /* enter critical */ 99 rt_enter_critical(); 100 101 /* for each network interfaces */ 102 information = rt_object_get_information(RT_Object_Class_Device); 103 RT_ASSERT(information != RT_NULL); 104 for (node = information->object_list.next; 105 node != &(information->object_list); 106 node = node->next) 107 { 108 object = rt_list_entry(node, struct rt_object, list); 109 device = (rt_device_t)object; 110 if (device->type == RT_Device_Class_NetIf) 111 { 112 ethif = (struct eth_device *)device; 113 114 /* leave critical */ 115 rt_exit_critical(); 116 LOCK_TCPIP_CORE(); 117 118 netif_add(ethif->netif, &ipaddr, &netmask, &gw, 119 ethif, netif_device_init, tcpip_input); 120 121 if (netif_default == RT_NULL) 122 netif_set_default(ethif->netif); 123 124 #if LWIP_DHCP 125 if (ethif->flags & NETIF_FLAG_DHCP) 126 { 127 /* if this interface uses DHCP, start the DHCP client */ 128 dhcp_start(ethif->netif); 129 } 130 else 131 #endif 132 { 133 /* set interface up */ 134 netif_set_up(ethif->netif); 135 } 136 137 if (!(ethif->flags & ETHIF_LINK_PHYUP)) 138 { 139 netif_set_link_up(ethif->netif); 140 } 141 142 UNLOCK_TCPIP_CORE(); 143 /* enter critical */ 144 rt_enter_critical(); 145 } 146 } 147 148 /* leave critical */ 149 rt_exit_critical(); 150 rt_sem_release((rt_sem_t)arg); 151 } 152 153 /** 154 * LwIP system initialization 155 */ 156 int lwip_system_init(void) 157 { 158 rt_err_t rc; 159 struct rt_semaphore done_sem; 160 161 /* set default netif to NULL */ 162 netif_default = RT_NULL; 163 164 rc = rt_sem_init(&done_sem, "done", 0, RT_IPC_FLAG_FIFO); 165 166 if (rc != RT_EOK) 167 { 168 LWIP_ASSERT("Failed to create semaphore", 0); 169 170 return -1; 171 } 172 173 tcpip_init(tcpip_init_done_callback, (void *)&done_sem); 174 175 /* waiting for initialization done */ 176 if (rt_sem_take(&done_sem, RT_WAITING_FOREVER) != RT_EOK) 177 { 178 rt_sem_detach(&done_sem); 179 180 return -1; 181 } 182 rt_sem_detach(&done_sem); 183 184 /* set default ip address */ 185 #if !LWIP_DHCP 186 if (netif_default != RT_NULL) 187 { 188 struct ip_addr ipaddr, netmask, gw; 189 190 ipaddr.addr = inet_addr(RT_LWIP_IPADDR); 191 gw.addr = inet_addr(RT_LWIP_GWADDR); 192 netmask.addr = inet_addr(RT_LWIP_MSKADDR); 193 194 netifapi_netif_set_addr(netif_default, &ipaddr, &netmask, &gw); 195 } 196 #endif 197 rt_kprintf("lwIP-%d.%d.%d initialized!\n", LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, LWIP_VERSION_REVISION); 198 199 return 0; 200 } 201 INIT_COMPONENT_EXPORT(lwip_system_init); 202 203 void sys_init(void) 204 { 205 /* nothing on RT-Thread porting */ 206 } 207 208 void lwip_sys_init(void) 209 { 210 lwip_system_init(); 211 } 212 213 /* 214 * Create a new semaphore 215 * 216 * @return the operation status, ERR_OK on OK; others on error 217 */ 218 err_t sys_sem_new(sys_sem_t *sem, u8_t count) 219 { 220 static unsigned short counter = 0; 221 char tname[RT_NAME_MAX]; 222 sys_sem_t tmpsem; 223 224 RT_DEBUG_NOT_IN_INTERRUPT; 225 226 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_SEM_NAME, counter); 227 counter ++; 228 229 tmpsem = rt_sem_create(tname, count, RT_IPC_FLAG_FIFO); 230 if (tmpsem == RT_NULL) 231 return ERR_MEM; 232 else 233 { 234 *sem = tmpsem; 235 236 return ERR_OK; 237 } 238 } 239 240 /* 241 * Deallocate a semaphore 242 */ 243 void sys_sem_free(sys_sem_t *sem) 244 { 245 RT_DEBUG_NOT_IN_INTERRUPT; 246 rt_sem_delete(*sem); 247 } 248 249 /* 250 * Signal a semaphore 251 */ 252 void sys_sem_signal(sys_sem_t *sem) 253 { 254 rt_sem_release(*sem); 255 } 256 257 /* 258 * Block the thread while waiting for the semaphore to be signaled 259 * 260 * @return If the timeout argument is non-zero, it will return the number of milliseconds 261 * spent waiting for the semaphore to be signaled; If the semaphore isn't signaled 262 * within the specified time, it will return SYS_ARCH_TIMEOUT; If the thread doesn't 263 * wait for the semaphore, it will return zero 264 */ 265 u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) 266 { 267 rt_err_t ret; 268 s32_t t; 269 u32_t tick; 270 271 RT_DEBUG_NOT_IN_INTERRUPT; 272 273 /* get the begin tick */ 274 tick = rt_tick_get(); 275 if (timeout == 0) 276 t = RT_WAITING_FOREVER; 277 else 278 { 279 /* convert msecond to os tick */ 280 if (timeout < (1000/RT_TICK_PER_SECOND)) 281 t = 1; 282 else 283 t = timeout / (1000/RT_TICK_PER_SECOND); 284 } 285 286 ret = rt_sem_take(*sem, t); 287 288 if (ret == -RT_ETIMEOUT) 289 return SYS_ARCH_TIMEOUT; 290 else 291 { 292 if (ret == RT_EOK) 293 ret = 1; 294 } 295 296 /* get elapse msecond */ 297 tick = rt_tick_get() - tick; 298 299 /* convert tick to msecond */ 300 tick = tick * (1000 / RT_TICK_PER_SECOND); 301 if (tick == 0) 302 tick = 1; 303 304 return tick; 305 } 306 307 #ifndef sys_sem_valid 308 /** Check if a semaphore is valid/allocated: 309 * return 1 for valid, 0 for invalid 310 */ 311 int sys_sem_valid(sys_sem_t *sem) 312 { 313 return (int)(*sem); 314 } 315 #endif 316 317 #ifndef sys_sem_set_invalid 318 /** Set a semaphore invalid so that sys_sem_valid returns 0 319 */ 320 void sys_sem_set_invalid(sys_sem_t *sem) 321 { 322 *sem = RT_NULL; 323 } 324 #endif 325 326 /* ====================== Mutex ====================== */ 327 328 /** Create a new mutex 329 * @param mutex pointer to the mutex to create 330 * @return a new mutex 331 */ 332 err_t sys_mutex_new(sys_mutex_t *mutex) 333 { 334 static unsigned short counter = 0; 335 char tname[RT_NAME_MAX]; 336 sys_mutex_t tmpmutex; 337 338 RT_DEBUG_NOT_IN_INTERRUPT; 339 340 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MUTEX_NAME, counter); 341 counter ++; 342 343 tmpmutex = rt_mutex_create(tname, RT_IPC_FLAG_FIFO); 344 if (tmpmutex == RT_NULL) 345 return ERR_MEM; 346 else 347 { 348 *mutex = tmpmutex; 349 350 return ERR_OK; 351 } 352 } 353 354 /** Lock a mutex 355 * @param mutex the mutex to lock 356 */ 357 void sys_mutex_lock(sys_mutex_t *mutex) 358 { 359 RT_DEBUG_NOT_IN_INTERRUPT; 360 rt_mutex_take(*mutex, RT_WAITING_FOREVER); 361 362 return; 363 } 364 365 /** Unlock a mutex 366 * @param mutex the mutex to unlock 367 */ 368 void sys_mutex_unlock(sys_mutex_t *mutex) 369 { 370 rt_mutex_release(*mutex); 371 } 372 373 /** Delete a semaphore 374 * @param mutex the mutex to delete 375 */ 376 void sys_mutex_free(sys_mutex_t *mutex) 377 { 378 RT_DEBUG_NOT_IN_INTERRUPT; 379 380 rt_mutex_delete(*mutex); 381 } 382 383 #ifndef sys_mutex_valid 384 /** Check if a mutex is valid/allocated: 385 * return 1 for valid, 0 for invalid 386 */ 387 int sys_mutex_valid(sys_mutex_t *mutex) 388 { 389 return (int)(*mutex); 390 } 391 #endif 392 393 #ifndef sys_mutex_set_invalid 394 /** Set a mutex invalid so that sys_mutex_valid returns 0 395 */ 396 void sys_mutex_set_invalid(sys_mutex_t *mutex) 397 { 398 *mutex = RT_NULL; 399 } 400 #endif 401 402 /* ====================== Mailbox ====================== */ 403 404 /* 405 * Create an empty mailbox for maximum "size" elements 406 * 407 * @return the operation status, ERR_OK on OK; others on error 408 */ 409 err_t sys_mbox_new(sys_mbox_t *mbox, int size) 410 { 411 static unsigned short counter = 0; 412 char tname[RT_NAME_MAX]; 413 sys_mbox_t tmpmbox; 414 415 RT_DEBUG_NOT_IN_INTERRUPT; 416 417 rt_snprintf(tname, RT_NAME_MAX, "%s%d", SYS_LWIP_MBOX_NAME, counter); 418 counter ++; 419 420 tmpmbox = rt_mb_create(tname, size, RT_IPC_FLAG_FIFO); 421 if (tmpmbox != RT_NULL) 422 { 423 *mbox = tmpmbox; 424 425 return ERR_OK; 426 } 427 428 return ERR_MEM; 429 } 430 431 /* 432 * Deallocate a mailbox 433 */ 434 void sys_mbox_free(sys_mbox_t *mbox) 435 { 436 RT_DEBUG_NOT_IN_INTERRUPT; 437 438 rt_mb_delete(*mbox); 439 440 return; 441 } 442 443 /** Post a message to an mbox - may not fail 444 * -> blocks if full, only used from tasks not from ISR 445 * @param mbox mbox to posts the message 446 * @param msg message to post (ATTENTION: can be NULL) 447 */ 448 void sys_mbox_post(sys_mbox_t *mbox, void *msg) 449 { 450 RT_DEBUG_NOT_IN_INTERRUPT; 451 452 rt_mb_send_wait(*mbox, (rt_uint32_t)msg, RT_WAITING_FOREVER); 453 454 return; 455 } 456 457 /* 458 * Try to post the "msg" to the mailbox 459 * 460 * @return return ERR_OK if the "msg" is posted, ERR_MEM if the mailbox is full 461 */ 462 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) 463 { 464 if (rt_mb_send(*mbox, (rt_uint32_t)msg) == RT_EOK) 465 return ERR_OK; 466 467 return ERR_MEM; 468 } 469 470 /** Wait for a new message to arrive in the mbox 471 * @param mbox mbox to get a message from 472 * @param msg pointer where the message is stored 473 * @param timeout maximum time (in milliseconds) to wait for a message 474 * @return time (in milliseconds) waited for a message, may be 0 if not waited 475 or SYS_ARCH_TIMEOUT on timeout 476 * The returned time has to be accurate to prevent timer jitter! 477 */ 478 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) 479 { 480 rt_err_t ret; 481 s32_t t; 482 u32_t tick; 483 484 RT_DEBUG_NOT_IN_INTERRUPT; 485 486 /* get the begin tick */ 487 tick = rt_tick_get(); 488 489 if(timeout == 0) 490 t = RT_WAITING_FOREVER; 491 else 492 { 493 /* convirt msecond to os tick */ 494 if (timeout < (1000/RT_TICK_PER_SECOND)) 495 t = 1; 496 else 497 t = timeout / (1000/RT_TICK_PER_SECOND); 498 } 499 500 ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, t); 501 if(ret == -RT_ETIMEOUT) 502 { 503 return SYS_ARCH_TIMEOUT; 504 } 505 else 506 { 507 LWIP_ASSERT("rt_mb_recv returned with error!", ret == RT_EOK); 508 } 509 510 /* get elapse msecond */ 511 tick = rt_tick_get() - tick; 512 513 /* convert tick to msecond */ 514 tick = tick * (1000 / RT_TICK_PER_SECOND); 515 if (tick == 0) 516 tick = 1; 517 518 return tick; 519 } 520 521 /** Wait for a new message to arrive in the mbox 522 * @param mbox mbox to get a message from 523 * @param msg pointer where the message is stored 524 * @param timeout maximum time (in milliseconds) to wait for a message 525 * @return 0 (milliseconds) if a message has been received 526 * or SYS_MBOX_EMPTY if the mailbox is empty 527 */ 528 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) 529 { 530 int ret; 531 532 ret = rt_mb_recv(*mbox, (rt_ubase_t *)msg, 0); 533 if(ret == -RT_ETIMEOUT) 534 { 535 return SYS_ARCH_TIMEOUT; 536 } 537 else 538 { 539 if (ret == RT_EOK) 540 ret = 1; 541 } 542 543 return ret; 544 } 545 546 #ifndef sys_mbox_valid 547 /** Check if an mbox is valid/allocated: 548 * return 1 for valid, 0 for invalid 549 */ 550 int sys_mbox_valid(sys_mbox_t *mbox) 551 { 552 return (int)(*mbox); 553 } 554 #endif 555 556 #ifndef sys_mbox_set_invalid 557 /** Set an mbox invalid so that sys_mbox_valid returns 0 558 */ 559 void sys_mbox_set_invalid(sys_mbox_t *mbox) 560 { 561 *mbox = RT_NULL; 562 } 563 #endif 564 565 /* ====================== System ====================== */ 566 567 /* 568 * Start a new thread named "name" with priority "prio" that will begin 569 * its execution in the function "thread()". The "arg" argument will be 570 * passed as an argument to the thread() function 571 */ 572 sys_thread_t sys_thread_new(const char *name, 573 lwip_thread_fn thread, 574 void *arg, 575 int stacksize, 576 int prio) 577 { 578 rt_thread_t t; 579 580 RT_DEBUG_NOT_IN_INTERRUPT; 581 582 /* create thread */ 583 t = rt_thread_create(name, thread, arg, stacksize, prio, 20); 584 RT_ASSERT(t != RT_NULL); 585 586 /* startup thread */ 587 rt_thread_startup(t); 588 589 return t; 590 } 591 592 sys_prot_t sys_arch_protect(void) 593 { 594 rt_base_t level; 595 596 /* disable interrupt */ 597 level = rt_hw_interrupt_disable(); 598 599 return level; 600 } 601 602 void sys_arch_unprotect(sys_prot_t pval) 603 { 604 /* enable interrupt */ 605 rt_hw_interrupt_enable(pval); 606 607 return; 608 } 609 610 void sys_arch_assert(const char *file, int line) 611 { 612 rt_kprintf("\nAssertion: %d in %s, thread %s\n", 613 line, file, rt_thread_self()->name); 614 RT_ASSERT(0); 615 } 616 617 u32_t sys_jiffies(void) 618 { 619 return rt_tick_get(); 620 } 621 622 u32_t sys_now(void) 623 { 624 return rt_tick_get() * (1000 / RT_TICK_PER_SECOND); 625 } 626 627 #ifdef RT_LWIP_PPP 628 u32_t sio_read(sio_fd_t fd, u8_t *buf, u32_t size) 629 { 630 u32_t len; 631 632 RT_ASSERT(fd != RT_NULL); 633 634 len = rt_device_read((rt_device_t)fd, 0, buf, size); 635 if (len <= 0) 636 return 0; 637 638 return len; 639 } 640 641 u32_t sio_write(sio_fd_t fd, u8_t *buf, u32_t size) 642 { 643 RT_ASSERT(fd != RT_NULL); 644 645 return rt_device_write((rt_device_t)fd, 0, buf, size); 646 } 647 648 void sio_read_abort(sio_fd_t fd) 649 { 650 rt_kprintf("read_abort\n"); 651 } 652 653 void ppp_trace(int level, const char *format, ...) 654 { 655 va_list args; 656 rt_size_t length; 657 static char rt_log_buf[RT_CONSOLEBUF_SIZE]; 658 659 va_start(args, format); 660 length = rt_vsprintf(rt_log_buf, format, args); 661 rt_device_write((rt_device_t)rt_console_get_device(), 0, rt_log_buf, length); 662 va_end(args); 663 } 664 #endif 665 666 /* 667 * export bsd socket symbol for RT-Thread Application Module 668 */ 669 #if LWIP_SOCKET 670 #include <lwip/sockets.h> 671 RTM_EXPORT(lwip_accept); 672 RTM_EXPORT(lwip_bind); 673 RTM_EXPORT(lwip_shutdown); 674 RTM_EXPORT(lwip_getpeername); 675 RTM_EXPORT(lwip_getsockname); 676 RTM_EXPORT(lwip_getsockopt); 677 RTM_EXPORT(lwip_setsockopt); 678 RTM_EXPORT(lwip_close); 679 RTM_EXPORT(lwip_connect); 680 RTM_EXPORT(lwip_listen); 681 RTM_EXPORT(lwip_recv); 682 RTM_EXPORT(lwip_read); 683 RTM_EXPORT(lwip_recvfrom); 684 RTM_EXPORT(lwip_send); 685 RTM_EXPORT(lwip_sendto); 686 RTM_EXPORT(lwip_socket); 687 RTM_EXPORT(lwip_write); 688 RTM_EXPORT(lwip_select); 689 RTM_EXPORT(lwip_ioctl); 690 RTM_EXPORT(lwip_fcntl); 691 692 RTM_EXPORT(lwip_htons); 693 RTM_EXPORT(lwip_ntohs); 694 RTM_EXPORT(lwip_htonl); 695 RTM_EXPORT(lwip_ntohl); 696 697 RTM_EXPORT(ipaddr_aton); 698 RTM_EXPORT(ipaddr_ntoa); 699 700 #if LWIP_DNS 701 #include <lwip/netdb.h> 702 RTM_EXPORT(lwip_gethostbyname); 703 RTM_EXPORT(lwip_gethostbyname_r); 704 RTM_EXPORT(lwip_freeaddrinfo); 705 RTM_EXPORT(lwip_getaddrinfo); 706 #endif 707 708 #endif 709 710 #if LWIP_DHCP 711 #include <lwip/dhcp.h> 712 RTM_EXPORT(dhcp_start); 713 RTM_EXPORT(dhcp_renew); 714 RTM_EXPORT(dhcp_stop); 715 #endif 716 717 #if LWIP_NETIF_API 718 #include <lwip/netifapi.h> 719 RTM_EXPORT(netifapi_netif_set_addr); 720 #endif 721 722 #if LWIP_NETIF_LINK_CALLBACK 723 RTM_EXPORT(netif_set_link_callback); 724 #endif 725 726 #if LWIP_NETIF_STATUS_CALLBACK 727 RTM_EXPORT(netif_set_status_callback); 728 #endif 729 730 RTM_EXPORT(netif_find); 731 RTM_EXPORT(netif_set_addr); 732 RTM_EXPORT(netif_set_ipaddr); 733 RTM_EXPORT(netif_set_gw); 734 RTM_EXPORT(netif_set_netmask); 735