| /* listener.c - Networking demo */ |
| |
| /* |
| * Copyright (c) 2015 Intel Corporation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <zephyr.h> |
| |
| #if defined(CONFIG_STDOUT_CONSOLE) |
| #include <stdio.h> |
| #define PRINT printf |
| #else |
| #include <misc/printk.h> |
| #define PRINT printk |
| #endif |
| |
| #include <net/ip_buf.h> |
| #include <net/net_core.h> |
| #include <net/net_socket.h> |
| |
| static void set_mac(void) |
| { |
| uint8_t mac[] = { 0x0a, 0xbe, 0xef, 0x15, 0xf0, 0x0d }; |
| |
| net_set_mac(mac, sizeof(mac)); |
| } |
| |
| #ifdef CONFIG_NETWORKING_WITH_IPV6 |
| /* The 2001:db8::/32 is the private address space for documentation RFC 3849 */ |
| #define MYADDR { { { 0x20,0x01,0x0d,0xb8,0,0,0,0,0,0,0,0,0,0,0,0x2 } } } |
| #else |
| /* The 192.0.2.0/24 is the private address space for documentation RFC 5737 */ |
| #define MYADDR { { { 192,0,2,2 } } } |
| #endif |
| |
| static struct net_context *get_context(void) |
| { |
| struct net_context *ctx; |
| static struct net_addr any_addr; |
| static struct net_addr my_addr; |
| |
| #ifdef CONFIG_NETWORKING_WITH_IPV6 |
| static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; |
| static struct in6_addr in6addr_my = MYADDR; |
| |
| any_addr.in6_addr = in6addr_any; |
| any_addr.family = AF_INET6; |
| |
| my_addr.in6_addr = in6addr_my; |
| my_addr.family = AF_INET6; |
| #else |
| static const struct in_addr in4addr_any = { { { 0 } } }; |
| static struct in_addr in4addr_my = MYADDR; |
| |
| any_addr.in_addr = in4addr_any; |
| any_addr.family = AF_INET; |
| |
| my_addr.in_addr = in4addr_my; |
| my_addr.family = AF_INET; |
| #endif |
| |
| ctx = net_context_get(IPPROTO_UDP, |
| &any_addr, 0, |
| &my_addr, 4242); |
| if (!ctx) { |
| PRINT("%s: Cannot get network context\n", __func__); |
| return NULL; |
| } |
| |
| return ctx; |
| } |
| |
| #ifdef CONFIG_MICROKERNEL |
| |
| /* |
| * Microkernel version of hello world demo has two tasks that utilize |
| * semaphores and sleeps to take turns printing a greeting message at |
| * a controlled rate. |
| */ |
| |
| /* specify delay between greetings (in ms); compute equivalent in ticks */ |
| |
| #define SLEEPTIME 500 |
| #define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000) |
| |
| /* specify delay between greetings (in ms); compute equivalent in ticks */ |
| |
| #define SLEEPTIME 500 |
| #define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000) |
| |
| /* |
| * |
| * @param taskname task identification string |
| * @param mySem task's own semaphore |
| * @param otherSem other task's semaphore |
| * |
| */ |
| void helloLoop(const char *taskname, ksem_t mySem, ksem_t otherSem) |
| { |
| static struct net_context *ctx; |
| struct net_buf *buf; |
| |
| net_init(); |
| |
| if (!ctx) { |
| ctx = get_context(); |
| } |
| |
| while (1) { |
| task_sem_take(mySem, TICKS_UNLIMITED); |
| |
| buf = net_receive(ctx, TICKS_NONE); |
| if (buf) { |
| PRINT("%s: received %d bytes\n", taskname, |
| ip_buf_appdatalen(buf)); |
| ip_buf_unref(buf); |
| } |
| |
| /* wait a while, then let other task have a turn */ |
| task_sleep(SLEEPTICKS); |
| task_sem_give(otherSem); |
| } |
| } |
| |
| void taskA(void) |
| { |
| set_mac(); |
| |
| /* taskA gives its own semaphore, allowing it to say hello right away */ |
| task_sem_give(TASKASEM); |
| |
| /* invoke routine that allows task to ping-pong hello messages with taskB */ |
| helloLoop(__func__, TASKASEM, TASKBSEM); |
| } |
| |
| void taskB(void) |
| { |
| /* invoke routine that allows task to ping-pong hello messages with taskA */ |
| helloLoop(__func__, TASKBSEM, TASKASEM); |
| } |
| |
| #else /* CONFIG_NANOKERNEL */ |
| |
| /* |
| * Nanokernel version of hello world demo has a task and a fiber that utilize |
| * semaphores and timers to take turns printing a greeting message at |
| * a controlled rate. |
| */ |
| |
| |
| /* specify delay between greetings (in ms); compute equivalent in ticks */ |
| |
| #define SLEEPTIME 500 |
| #define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000) |
| |
| #define STACKSIZE 2000 |
| |
| char fiberStack[STACKSIZE]; |
| |
| struct nano_sem nanoSemTask; |
| struct nano_sem nanoSemFiber; |
| |
| void fiberEntry(void) |
| { |
| struct nano_timer timer; |
| uint32_t data[2] = {0, 0}; |
| struct net_context *ctx; |
| struct net_buf *buf; |
| |
| ctx = get_context(); |
| if (!ctx) { |
| PRINT("%s: Cannot get network context\n", __func__); |
| return; |
| } |
| |
| nano_sem_init (&nanoSemFiber); |
| nano_timer_init (&timer, data); |
| |
| while (1) { |
| /* wait for task to let us have a turn */ |
| nano_fiber_sem_take(&nanoSemFiber, TICKS_UNLIMITED); |
| |
| buf = net_receive(ctx, TICKS_NONE); |
| if (buf) { |
| PRINT("%s: received %d bytes\n", __func__, |
| ip_buf_appdatalen(buf)); |
| ip_buf_unref(buf); |
| } |
| |
| /* wait a while, then let task have a turn */ |
| nano_fiber_timer_start (&timer, SLEEPTICKS); |
| nano_fiber_timer_test(&timer, TICKS_UNLIMITED); |
| nano_fiber_sem_give (&nanoSemTask); |
| } |
| } |
| |
| void main(void) |
| { |
| struct nano_timer timer; |
| uint32_t data[2] = {0, 0}; |
| |
| net_init(); |
| |
| PRINT("%s: run listener\n", __func__); |
| |
| set_mac(); |
| |
| task_fiber_start (&fiberStack[0], STACKSIZE, |
| (nano_fiber_entry_t) fiberEntry, 0, 0, 7, 0); |
| |
| nano_sem_init(&nanoSemTask); |
| nano_timer_init(&timer, data); |
| |
| while (1) { |
| /* wait a while, then let fiber have a turn */ |
| nano_task_timer_start(&timer, SLEEPTICKS); |
| nano_task_timer_test(&timer, TICKS_UNLIMITED); |
| nano_task_sem_give(&nanoSemFiber); |
| |
| /* now wait for fiber to let us have a turn */ |
| nano_task_sem_take(&nanoSemTask, TICKS_UNLIMITED); |
| } |
| } |
| |
| #endif /* CONFIG_MICROKERNEL || CONFIG_NANOKERNEL */ |