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