/* * UdpBytewise.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. * Drop UdpBytewise.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/ * TODO: should protect buffer access with critical sections * * MIT License: * Copyright (c) 2008 Bjoern Hartmann * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * bjoern@cs.stanford.edu 12/30/2008 */ extern "C" { #include "types.h" #include "w5100.h" #include "socket.h" } #include "Ethernet.h" #include "UdpBytewise.h" /* Start UDP socket, listening at local port PORT */ void UdpBytewiseClass::begin(uint16_t port) { _port = port; _sock = 0; //TODO: should not be hardcoded _txIndex =0; _rxIndex =0; _rxSize = 0; _txOverflowStrategy = UDP_TX_OVERFLOW_SPLIT; socket(_sock,Sn_MR_UDP,_port,0); } /* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes. */ int UdpBytewiseClass::available() { if(_rxSize==0 || _rxSize-_rxIndex==0) { //if local buffer is empty or depleted //check wiz5100 buffer for new packet _rxSize = getSn_RX_RSR(_sock); //note: return value is inflated by 8 byte header if(_rxSize){ //if we have a new packet there //reset buffer index _rxIndex=0; //copy packet into our local buffer _rxSize = recvfrom(_sock,_rxBuffer,_rxSize-8,_rxIp,&_rxPort); } else { //else do nothing and rxsize is still 0 ; } return _rxSize; //return the new number of bytes in our buffer } else{ //if buffer is not empty, return remaining # of bytes return (_rxSize-_rxIndex); } } /* Start a new packet with given target ip and port * returns 1 on success, 0 if we already started a packet */ int UdpBytewiseClass::beginPacket(uint8_t *ip, unsigned int port) { if(_txIndex==0) { //ok to start new packet - copy ip and port _txIp[0]=ip[0]; _txIp[1]=ip[1]; _txIp[2]=ip[2]; _txIp[3]=ip[3]; _txPort = port; return 1; } else { //we already started a packet and have data in it return 0; } } /* Add a byte to the currently assembled packet if there is space * if there isn't space, either truncate (ignore) or split the packet. */ void UdpBytewiseClass::write(uint8_t b) { if(_txIndex>= UDP_TX_PACKET_MAX_SIZE) { //buffer is full - we can either truncate the packet or split in two switch (_txOverflowStrategy) { case UDP_TX_OVERFLOW_SPLIT: endPacket(); beginPacket(_txIp,_txPort); //fall through to normal add of byte to buffer below break; case UDP_TX_OVERFLOW_TRUNCATE: default: //don't add - just ignore bytes past buffer size return; } } _txBuffer[_txIndex++] = b; } /* send an assembled packet out * returns # of bytes sent on success, 0 if there's nothing to send */ int UdpBytewiseClass::endPacket() { // send the packet uint16_t result = sendto(_sock,(const uint8_t *)_txBuffer,_txIndex,_txIp,_txPort); // reset buffer index _txIndex=0; // return sent bytes return (int)result; } /* read the next byte of the last rececived packet */ int UdpBytewiseClass::read() { if(_rxIndex < _rxSize) { // if there is something to be read, return the next byte return _rxBuffer[_rxIndex++]; } else { //we already sent the last byte - nothing to do return -1; } } void UdpBytewiseClass::getSenderIp(uint8_t*ip) { ip[0]=_rxIp[0]; ip[1]=_rxIp[1]; ip[2]=_rxIp[2]; ip[3]=_rxIp[3]; } unsigned int UdpBytewiseClass::getSenderPort() { return _rxPort; } /* what should we do when we try to add to a full outgoing packet? * UDP_TX_OVERFLOW_TRUNCATE - throw overflow bytes away * UDP_TX_OVERFLOW_SPLIT - split into multiple packets */ void UdpBytewiseClass::setOverflowStrategy(uint8_t strategy) { _txOverflowStrategy = strategy; } /* Create one global object */ UdpBytewiseClass UdpBytewise;