From 2068d1ff601ff5b39d17594b48a4bbec1ac0fb96 Mon Sep 17 00:00:00 2001 From: Peter Kwan Date: Thu, 10 Aug 2017 11:03:51 +0100 Subject: [PATCH] Skeleton of packet source set up Base class for packet generating which will be used to create magazine, subtitle, packet 830 and databroadcast packet sources. --- TCPClient.cpp | 28 +++++++------ command.cpp | 24 +++++------ command.h | 32 +++++++-------- packetsource.cpp | 31 ++++++++++++++ packetsource.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 40 deletions(-) create mode 100644 packetsource.cpp create mode 100644 packetsource.h diff --git a/TCPClient.cpp b/TCPClient.cpp index 0ded5e6..aeade78 100644 --- a/TCPClient.cpp +++ b/TCPClient.cpp @@ -31,11 +31,11 @@ void TCPClient::command(char* cmd, char* response) { switch (cmd[0]) { - case 'T' :; + case 'T' :; if (response) strcpy(response,"T not implemented\n"); break; - - case 'Y' : + + case 'Y' : if (response) strcpy(response,"VBIT620\n"); break; case 0x0e: @@ -51,7 +51,7 @@ void TCPClient::clearCmd(void) } /** AddChar - * Add a char to the command buffer and call command when we get CR + * Add a char to the command buffer and call command when we get CR * There is only a response if a command needs to send something back. * If the first character is a Newfor character then the data is parsed as Nu4. * Commands that are not Newfor are MODENORMAL. They are stateless (so far) @@ -80,14 +80,14 @@ void TCPClient::addChar(char ch, char* response) charCount=4; break; case 0x0f : - mode=MODEGETROWCOUNT; // n and n*(rowhigh, rowlow, 40 bytes) + mode=MODEGETROWCOUNT; // n and n*(rowhigh, rowlow, 40 bytes) break; case 0x10 : // Put the subtitle on air immediately _newfor.SubtitleOnair(response); // std::cerr << "[TCPClient::addChar] On air" << std::endl; clearCmd(); - mode=MODENORMAL; + mode=MODENORMAL; return; case 0x18 : // Remove the subtitle immediately @@ -95,7 +95,7 @@ void TCPClient::addChar(char ch, char* response) _newfor.SubtitleOffair(); strcpy(response, "[addChar]Clear"); clearCmd(); - mode=MODENORMAL; + mode=MODENORMAL; return; } } // If first character @@ -112,11 +112,11 @@ void TCPClient::addChar(char ch, char* response) std::cerr << "[TCPClient::addChar] finished cmd=" << _cmd << std::endl; command(_cmd, response); clearCmd(); - mode=MODENORMAL; + mode=MODENORMAL; } break; // Message type 1 - Set subtitle page. - case MODESOFTELPAGEINIT: // We get four more characters and then the page is set + case MODESOFTELPAGEINIT: // We get four more characters and then the page is set // @todo If a nybble fails deham or isn't in range we should return nack // std::cerr << "[TCPClient::addChar] Page init char=" << ((int)ch) << std::endl; *_pCmd++=ch; @@ -176,11 +176,11 @@ void TCPClient::addChar(char ch, char* response) // Now that we are done, set up for the next command sprintf(response,"subtitle data complete\n"); mode=MODENORMAL; - clearCmd(); + clearCmd(); } } break; - } // State machine switch + } // State machine switch } @@ -196,7 +196,7 @@ void TCPClient::Handler(int clntSocket) int i; clearCmd(); // std::cerr << "[TCPClient::Handler]" << std::endl; - + /* Send received string and receive again until end of transmission */ for (recvMsgSize=1;recvMsgSize > 0;) /* zero indicates end of transmission */ { @@ -213,6 +213,10 @@ void TCPClient::Handler(int clntSocket) // DieWithError("send() failed"); } +#ifdef WIN32 + // @todo What is the Windows way? +#else close(clntSocket); /* Close client socket */ +#endif // WIN32 } diff --git a/command.cpp b/command.cpp index 66425fd..8894c46 100644 --- a/command.cpp +++ b/command.cpp @@ -36,7 +36,7 @@ Command::Command(const uint32_t port=5570) : _portNumber(port) { // Constructor - // Start a listener thread + // Start a listener thread } Command::~Command() @@ -54,16 +54,16 @@ void Command::run() { std::cerr << "[Command::run] Newfor subtitle listener started" << std::endl; int serverSock; /* Socket descriptor for server */ - int clientSock; /* Socket descriptor for client */ + int clientSock; /* Socket descriptor for client */ struct sockaddr_in echoServAddr; /* Local address */ - struct sockaddr_in echoClntAddr; /* Client address */ - unsigned short echoServPort; /* Server port */ + struct sockaddr_in echoClntAddr; /* Client address */ + unsigned short echoServPort; /* Server port */ #ifdef WIN32 int clntLen; /* needs to be signed int for winsock */ WSADATA wsaData; int iResult; - + // Initialize Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaData); if (iResult != 0) { @@ -74,7 +74,7 @@ void Command::run() #endif echoServPort = _portNumber; /* This is the local port */ - + // System initialisations /* Construct local address structure */ std::memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ @@ -84,27 +84,27 @@ void Command::run() /* Create socket for incoming connections */ if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - DieWithError("socket() failed\n"); - + DieWithError("socket() failed\n"); + /* Bind to the local address */ if (bind(serverSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) DieWithError("bind() failed"); /* Mark the socket so it will listen for incoming connections */ if (listen(serverSock, MAXPENDING) < 0) - DieWithError("listen() failed"); + DieWithError("listen() failed"); /* Set the size of the in-out parameter */ clntLen = sizeof(echoClntAddr); - + TCPClient client; - + while(1) { std::cerr << "[Command::run] Ready for a client to connect" << std::endl; /* Wait for a client to connect */ - if ((clientSock = accept(serverSock, (struct sockaddr *) &echoClntAddr, + if ((clientSock = accept(serverSock, (struct sockaddr *) &echoClntAddr, &clntLen)) < 0) DieWithError("accept() failed"); std::cerr << "[Command::run] Connected" << std::endl; diff --git a/command.h b/command.h index 7ded9c7..23370a7 100644 --- a/command.h +++ b/command.h @@ -5,7 +5,7 @@ * Compiler : C++ * @author Peter Kwan * @date July, 2017 - * + * * Copyright (C) 2017, Peter Kwan * * Permission to use, copy, modify, and distribute this software @@ -64,36 +64,36 @@ class Command * @brief Constructor * @description Listens on port 5570 and accepts connections. * When connected it can be sent Newfor commands. - */ + */ Command(const uint32_t port); - + /** * @brief Constructor * @param port - TCP port number to use - */ - Command(int port); - + */ + Command(int port); + /** * @brief Destructor - */ + */ ~Command(); - + /** - * @brief Run the listener thread. - */ + * @brief Run the listener thread. + */ void run(); - + private: int _portNumber; - + /* Page init and subtitle data can respond with this standard codes */ static const uint8_t ASCII_ACK=0x06; static const uint8_t ASCII_NACK=0x15; - static const uint8_t MAXPENDING=5; /* Maximum outstanding connection requests */ - + static const uint8_t MAXPENDING=5; /* Maximum outstanding connection requests */ + void DieWithError(std::string errorMessage); /* Error handling function */ - - + + }; // Command } // namespace vbit diff --git a/packetsource.cpp b/packetsource.cpp new file mode 100644 index 0000000..6614d22 --- /dev/null +++ b/packetsource.cpp @@ -0,0 +1,31 @@ +#include "packetsource.h" + +using namespace vbit; + +PacketSource::PacketSource() +{ + //ctor +} + +PacketSource::~PacketSource() +{ + //dtor +} + + +Packet* PacketSource::GetPacket() +{ + Packet* pkt=new Packet(8,25," "); + // Do your stuff + return pkt; +} + +bool PacketSource::IsReady() +{ + return false; // @todo This will probably just return a member bool +} + +void PacketSource::SetEvent(Event event) +{ + //@todo Use event to clear the event flags which may have been set by the packet source being in wait. +} diff --git a/packetsource.h b/packetsource.h new file mode 100644 index 0000000..6805ef0 --- /dev/null +++ b/packetsource.h @@ -0,0 +1,102 @@ +/** *************************************************************************** + * Description : Interface for sources of packets: mag, subtitles etc. + * Compiler : C++ + * + * Copyright (C) 2017, Peter Kwan + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaims all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author be liable for any + * special, indirect or consequential damages or any damages + * whatsoever resulting from loss of use, data or profits, whether + * in an action of contract, negligence or other tortious action, + * arising out of or in connection with the use or performance of + * this software. + *************************************************************************** +**/ +/** + * Anything that generates teletext packets is derived from this interface. + * Functions defined by this interface are + * Constructor - sets up the data required by a particular packet source. + * GetPacket - Gets the next packet in the stream. + * Waiting - The stream is waiting for an event to restart it + * SetEvent - Registers an even with the packet source + * + * Teletext packets come in four broad categories + * 1) Magazines - Rows consisting of headers and body rows. + * 2) Subtitles - Same as magazines but sent at highest priority. + * 3) Packets on magazine 8, row 30 - Timing and control that happen on specific fields. + * 4) Databroadcast - Packets that get sent at low priority and when possible. + * + * Events + * 1) Field + * 2) 10 fields + * 3) Subtitle data in buffer + * 4) All other streams are waiting (so we can now send databroadcast) +**/ +#ifndef _PACKETSOURCE_H_ +#define _PACKETSOURCE_H_ + +#include "packet.h" + +namespace vbit{ + +/** @brief Events are used to trigger packet sources so that they may proceed + * @description Different packet sources use different timing schemes. + * Packet sources may put themselves into a waiting state. + * Events are used to start them up again. + * Magazines stop after a header and wait for the next field. + * Subtitles wait until there is data in the subtitle buffer. + * Packet 830 waits for a multiple of 10 fields. + * Databroadcast varies according to the importance of the signal. + * Lowest priority may only jump in only when a filler packet would be sent. + * Highest priority might steal all the packets except for 830. + */ +enum Event +{ + EVENT_FIELD, + EVENT_P830_FORMAT_1, + EVENT_P830_FORMAT_2_LABEL_0, + EVENT_P830_FORMAT_2_LABEL_1, + EVENT_P830_FORMAT_2_LABEL_2, + EVENT_P830_FORMAT_2_LABEL_3, + EVENT_SUBTITLE, + EVENT_DATABROADCAST +} ; + + +class PacketSource +{ + public: + /** Default constructor */ + PacketSource(); + /** Default destructor */ + virtual ~PacketSource(); + + /** Get the next packet + * @return The next packet OR if IsReady() would return false then a filler packet + */ + virtual Packet* GetPacket()=0; + + /** Is there a packet ready to go? */ + virtual bool IsReady(); // Don't need to Pure this. Just report a member bool + + /** Report that an event happened */ + virtual void SetEvent(Event event); // Don't need to Pure this. All packet sources can use the same code + + protected: + private: +}; + +} // vbit namespace + +#endif // _PACKETSOURCE_H_