📄 net.c
字号:
// This file is part of MANTIS OS, Operating System// See http://mantis.cs.colorado.edu///// Copyright (C) 2003,2004,2005 University of Colorado, Boulder//// This program is free software; you can redistribute it and/or// modify it under the terms of the mos license (see file LICENSE)/**************************************************************************//* File: net.c *//* Author: Jeff Rose : rosejn@colorado.edu *//* Author: Charles Gruenwald III : gruenwal@colorado.edu *//* Date: 04/15/04 *//* Modified: Cyrus Hall : hallcp@colorado.edu *//* Date: 07/22/04 *//* *//* Top level event based networking layer. *//**************************************************************************//** @file net.c * @brief Top level event based networking layer. * @author Jeff Rose, Charles Gruenwald III * @author Modified: Cyrus Hall * @date Created: 04/15/2004 * @date Modified: 07/22/2004 */#include "net.h"#include "msched.h" /** @brief List of current protocols. */net_proto protocols[NET_PROTO_MAX];/** @brief default_protocol **/uint8_t default_proto;/** @brief pointer to last received comBuf **/comBuf * currentComBuf;/** @brief list of threads blocked on recv **/static thread_t *waitingThreads;static mos_mutex_t netMutex;#ifdef MOS_NO_USE_DYNAMIC_MEMORYstatic uint8_t net_stack[192];#endif/** @brief Initialize the net layer variables */void net_init(){ uint8_t i; for(i = 0; i < NET_PROTO_MAX; i++) protocols[i].proto_id = 0; currentComBuf = NULL; waitingThreads = NULL; mos_mutex_init(&netMutex);#ifdef MOS_NO_USE_DYNAMIC_MEMORY mos_thread_new_havestack(net_thread, 192, net_stack, PRIORITY_NORMAL);#else mos_thread_new(net_thread, 192, PRIORITY_NORMAL);#endif}/** @brief net_send method called by applications * @param pkt comBuf from application * @param proto_id protocol's ID * @param port destination port * @return ret not useful so far.. should probably return number of bytes sent? */int8_t net_send(comBuf *pkt, uint8_t proto_id, uint8_t port, ...){ uint8_t i; va_list ap; uint8_t ret; uint8_t old_size; if(proto_id == 0) return NET_PROTO_INVALID; /* store the old size since we modify it */ old_size = pkt->size; /* Make sure we have a valid protocol id, then send. */ for(i = 0; i < NET_PROTO_MAX; i++) { if(protocols[i].proto_id == proto_id) { /* Setup the va_list. */ va_start(ap, port); /* Now send to protocol to add protocol specific footers. */ ret = protocols[i].sfunc(pkt, ap); va_end(ap); /* add the dest port to the packet footer*/ pkt->data[pkt->size] = port; pkt->size++; /* add the protocol id to the packet footer*/ pkt->data[pkt->size] = proto_id; pkt->size++; /*the net layer actually sends the packet */#ifdef PLATFORM_AVRDEV com_send(IFACE_SERIAL2, pkt);#else com_send(IFACE_RADIO, pkt);#endif // set the packet size to be its original size // since we modified it pkt->size = old_size; return ret; } } /* Not a valid protocol. */ return NET_PROTO_INVALID;}/* * @param sfunc Protocol send function * @param rfunc Protocol receive function * @param ifunc Protocol io control function * @return NET_PROTO_INVALID if protocol invalid, -1 if no space left, else return */int8_t net_proto_register(uint8_t proto, net_proto_send sfunc, net_proto_recv rfunc, net_proto_ioctl ifunc){ uint8_t i; /* Make sure the passed in ID is valid, i.e., not 0. */ if(proto == 0) return NET_PROTO_INVALID; /* Find the next available slot. */ for(i = 0; i < NET_PROTO_MAX; i++) { if(protocols[i].proto_id == proto || protocols[i].proto_id == 0) { protocols[i].proto_id = proto; protocols[i].sfunc = sfunc; protocols[i].rfunc = rfunc; protocols[i].ifunc = ifunc; return 0; } } /* No space left. */ return -1;}/** @brief Set some protocol specific options. * @param proto Protocol * @param request IO Request * @return NET_PROTO_INVALID if protocol invalid, else return retval */int8_t net_ioctl(uint8_t proto, uint8_t request, ...){ uint8_t i; uint8_t retval; va_list ap; if(proto == 0) return NET_PROTO_INVALID; /* Make sure we have a valid protocol id, then call the func. */ for(i = 0; i < NET_PROTO_MAX; i++) { if(protocols[i].proto_id == proto) { /* Now ship it off to the protocol. */ va_start(ap, request); retval = protocols[i].ifunc(request, ap); va_end(ap); return retval; } } /* Not a valid protocol. */ return NET_PROTO_INVALID;}/** @brief A background thread that listens on everything for event traffic.*/void net_thread(){ comBuf *pkt; uint8_t i; uint8_t proto; uint8_t port; uint8_t *footer; boolean toApp;#ifdef PLATFORM_AVRDEV com_mode(IFACE_SERIAL2, IF_LISTEN);#else com_mode(IFACE_RADIO, IF_LISTEN);#endif while(1) {#ifdef PLATFORM_AVRDEV pkt = com_recv(IFACE_SERIAL2);#else pkt = com_recv(IFACE_RADIO);#endif /* Now that we have a packet we pull the protocol ID and port and send it to the correct protocol handler. */ proto = pkt->data[pkt->size - 1]; pkt->size--; port = pkt->data[pkt->size - 1]; pkt->size--; /* If the proto is 0, we've received an invalid packet. */ if(proto == 0) { com_free_buf(pkt); continue; } for(i = 0; i < NET_PROTO_MAX && protocols[i].proto_id != proto; i++); /* Bogus protocol id... */ if(i == NET_PROTO_MAX) { com_free_buf(pkt); continue; } /* set the current comBuf to the currently received packet */ currentComBuf = pkt; /* check to see if the protocol is going to send the packet to the app */ toApp = protocols[i].rfunc(pkt, &footer, port); /* if it doesn't free the buffer. If it does, it's the Apps job to free the buffer */ if (!toApp){ com_free_buf(pkt); } }}/** @brief is_app_waiting_on() method called by protocols * @param port check all waiting threads for the specified port * @return true if it sent the packet to an app, false if it did not. */boolean is_app_waiting_on(uint8_t port){ thread_t *current; thread_t *previous; mos_mutex_lock(&netMutex); previous = waitingThreads; current = waitingThreads; /* first check to see if the first thread is waiting on the specified port */ if (previous->port == port) { waitingThreads = waitingThreads->next; //give current packet back to app mos_thread_resume(current); mos_mutex_unlock(&netMutex); return true; } /* it wasn't the first thread, so check the rest */ current = current->next; while (current != NULL) { /* found a waiting thread */ if (current->port == port) { /* remove it from list */ previous->next = current->next; /* resume the app (gives the current packet to the app) */ mos_thread_resume(current); mos_mutex_unlock(&netMutex); return true; } current = current->next; previous = previous->next; } mos_mutex_unlock(&netMutex); return false; } /** @brief net_recv method called by applications * @param port listening on specified port * @return returns comBuf to application */comBuf *net_recv(uint8_t port){ thread_t *head; /* set the port the thread will wait on */ mos_thread_set_port(port); mos_mutex_lock(&netMutex); /* if no threads waiting, make this the first in the list */ if (waitingThreads == NULL){ waitingThreads = mos_thread_current(); } /* otherwise, add it to the end of the list of waiting threads */ else { head = waitingThreads; while (head->next != NULL){ head = head->next; } head->next = mos_thread_current(); } mos_mutex_unlock(&netMutex); /* suspend the thread until a packet with the specified port is received */ mos_thread_suspend(); /* we've been woken up by the is_app_waiting_on(port) call, so the current packet must be for this app */ return currentComBuf; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -