diff --git a/TCPClient.cpp b/TCPClient.cpp index e94e1ff..d022726 100644 --- a/TCPClient.cpp +++ b/TCPClient.cpp @@ -8,17 +8,17 @@ using namespace vbit; using namespace ttx; static int -vbi_unham8 (unsigned int c) +vbi_unham8(unsigned int c) { - return _vbi_hamm8_inv[(uint8_t) c]; + return Hamming8DecodeTable[(uint8_t) c]; } TCPClient::TCPClient(PacketSubtitle* subtitle, PageList* pageList) : - _pCmd(_cmd), - _newfor(subtitle), - _pageList(pageList) + _pCmd(_cmd), + _newfor(subtitle), + _pageList(pageList) { - strcpy(_pageNumber,"10000"); + strcpy(_pageNumber,"10000"); } TCPClient::~TCPClient() @@ -33,223 +33,225 @@ void TCPClient::DieWithError(std::string errorMessage) void TCPClient::command(char* cmd, char* response) { - char result[132]; - char* ptr; - int row; - int status=0; - //char statusText[4]; + char result[132]; + char* ptr; + int row; + int status=0; + //char statusText[4]; #ifdef DEBUG - strcpy(response,"todo"); + strcpy(response,"todo"); #endif - switch (cmd[0]) - { - case 'D' : // D[][] - directory - // = F | L - // = + | - - // = number of pages to step through (default 1) + switch (cmd[0]) { - TTXPageStream* page=nullptr; - int ix=1; - switch (cmd[ix]) - { - case 'F' : // Move to first page - std::cerr << "DF" << std::endl; - ix++; - if ((page=_pageList->FirstPage())==nullptr) + case 'D' : // D[][] - directory + // = F | L + // = + | - + // = number of pages to step through (default 1) { - status=1; // Fail: There are no pages selected - break; + TTXPageStream* page=nullptr; + int ix=1; + switch (cmd[ix]) + { + case 'F' : // Move to first page + std::cerr << "DF" << std::endl; + ix++; + if ((page=_pageList->FirstPage())==nullptr) + { + status=1; // Fail: There are no pages selected + break; + } + status=0; + break; + case '+' : // Step to next entry + page=_pageList->NextPage(); + if (page!=nullptr) + { + status=0; + } + else + { + status=1; + } + break; + case '-' : // Step to previous entry + page=_pageList->PrevPage(); + if (page!=nullptr) + { + status=0; + } + else + { + status=1; + } + break; + case 'L' : // Move to last page + std::cerr << "DL" << std::endl; + ix++; + if ((page=_pageList->LastPage())==nullptr) + { + status=1; // Fail: There are no pages selected + break; + } + status=0; + break; + case 'P' : // Secret debug code - Sends page into to stderr + std::cerr << "DP" << std::endl; + page=_pageList->FirstPage(); + for (int row=0;row<24;row++) + { + std::cerr << "OL," << std::setw(2) << row; + TTXLine* line=page->GetRow(row); + std::cerr << "," << line->GetLine() << std::endl; + } + status=0; + break; + default: + status=1; + strcpy(result,"This was unexpected"); + } + // Now we either have a page pointer or null + if (status==0) + { + // ss mpp qq cc tttt ssss n xxxxxxxx + sprintf(result,"%02d %03x %02d %02d %04x %1d %s", + page->GetSubCode(), + page->GetPageNumber(), + page->GetCycleTime(), + page->GetSubCode(), + page->GetPageStatus(), + 0, + "????????"); + } + else if (status==1) + { + result[0]=0; + } + break; } - status=0; - break; - case '+' : // Step to next entry - page=_pageList->NextPage(); - if (page!=nullptr) + case 'L' : // L - Set row in current page with text { - status=0; + char rowStr[3]; + rowStr[0]=cmd[1]; + rowStr[1]=cmd[2]; + rowStr[2]=0; + row=std::strtol(rowStr, &ptr, 10); + ptr=&(cmd[3]); + result[0]=0; + status=0; // @todo Line number out of range =1 + //sprintf(result, "L Command Page=%.*s row=%d ptr=%s\n\r", 5, _pageNumber, row, ptr); + std::cerr << "[TCPClient::command] L command starts" << std::endl; + for (TTXPageStream* p=_pageList->FirstPage(); p!=nullptr; p=_pageList->NextSelectedPage()) + { + TTXPageStream* page=p; + std::cerr << "[TCPClient::command] L command applied to page=" << std::hex << page->GetPageNumber() << std::endl; + page->SetRow(row, ptr); + } + break; } - else + case 'M' : // MD - delete pages { - status=1; + status=1; // Incorrect syntax or no page deleted. + result[0]=0; + if (cmd[1]=='D') + { + for (TTXPageStream* p=_pageList->NextSelectedPage(); + p!=nullptr; + p=_pageList->NextSelectedPage()) + { + TTXPageStream* page=p; + std::cerr << "[TCPClient::command] MD command applied to page=" << std::hex << page->GetPageNumber() << std::endl; + status=0; + // @todo Actually delete the page from _pageList + } + } + break; } - break; - case '-' : // Step to previous entry - page=_pageList->PrevPage(); - if (page!=nullptr) + case 'P' : // P - Set the page number. @todo Extend to multiple page selection { - status=0; + char* param=&(cmd[1]); // The page identity parameter + char* pageSet=_pageNumber;// The validated page identity + int matchedPages=-1; + if (Validate(pageSet, param)) + { + matchedPages=_pageList->Match(pageSet); + } + // pageSet is empty + if (matchedPages==0) + { + matchedPages=1; + status=8; + for (int i=0;i<5;i++) // Wildcards are not allowed here + { + if (_pageNumber[i]=='*') + { + matchedPages=-1; // fail + } + } + // @todo Create the page if status is 8 + if (status==8) + { + std::cerr << "[TCPClient::command] @todo Create the page" << std::endl; + } + } + // Failed command + if (matchedPages<0) + { + matchedPages=0; + status=1; + } + _pageNumber[5]=0; // Terminate the page number before we print it just in case + std::cerr << "[TCPClient::command] _pageNumber=" << _pageNumber << std::endl; + sprintf(result,"%03d",matchedPages); + break; } - else + case 'R' : // R - Read back row from the first selected page { - status=1; + TTXPageStream* p; + char rowStr[3]; + rowStr[0]=cmd[1]; + rowStr[1]=cmd[2]; + rowStr[2]=0; + row=std::strtol(rowStr, &ptr, 10); + p=_pageList->FirstPage(); + if (p==nullptr) + { + result[0]=0; + status=1; + } + else + { + TTXLine* line=p->GetRow(row); + strcpy(result,line->GetLine().c_str()); + } + break; } - break; - case 'L' : // Move to last page - std::cerr << "DL" << std::endl; - ix++; - if ((page=_pageList->LastPage())==nullptr) + case 'T' :; { - status=1; // Fail: There are no pages selected - break; + strcpy(result,"T not implemented\n\r"); + break; } - status=0; - break; - case 'P' : // Secret debug code - Sends page into to stderr - std::cerr << "DP" << std::endl; + case 'Y' : { - page=_pageList->FirstPage(); - for (int row=0;row<24;row++) - { - std::cerr << "OL," << std::setw(2) << row; - TTXLine* line=page->GetRow(row); - std::cerr << "," << line->GetLine() << std::endl; - } + snprintf(result,33,"VBIT620 Text Generator %s",VBIT2_VERSION); + break; } - status=0; - break; - default: - status=1; - strcpy(result,"This was unexpected"); - } - // Now we either have a page pointer or null - if (status==0) - { - // ss mpp qq cc tttt ssss n xxxxxxxx - sprintf(result,"%02d %03x %02d %02d %04x %1d %s", - page->GetSubCode(), - page->GetPageNumber(), - page->GetCycleTime(), - page->GetSubCode(), - page->GetPageStatus(), - 0, - "????????"); - } - else if (status==1) - { - result[0]=0; - } - break; - - } // D command - case 'L' : // L - Set row in current page with text - { - char rowStr[3]; - - rowStr[0]=cmd[1]; - rowStr[1]=cmd[2]; - rowStr[2]=0; - row=std::strtol(rowStr, &ptr, 10); - ptr=&(cmd[3]); - result[0]=0; - status=0; // @todo Line number out of range =1 - //sprintf(result, "L Command Page=%.*s row=%d ptr=%s\n\r", 5, _pageNumber, row, ptr); - - std::cerr << "[TCPClient::command] L command starts" << std::endl; - for (TTXPageStream* p=_pageList->FirstPage(); - p!=nullptr; - p=_pageList->NextSelectedPage()) - { - TTXPageStream* page=p; - std::cerr << "[TCPClient::command] L command applied to page=" << std::hex << page->GetPageNumber() << std::endl; - page->SetRow(row, ptr); - } - - } - break; - case 'M' : // MD - delete pages - status=1; // Incorrect syntax or no page deleted. - result[0]=0; - if (cmd[1]=='D') - { - for (TTXPageStream* p=_pageList->NextSelectedPage(); - p!=nullptr; - p=_pageList->NextSelectedPage()) - { - TTXPageStream* page=p; - std::cerr << "[TCPClient::command] MD command applied to page=" << std::hex << page->GetPageNumber() << std::endl; - status=0; - // @todo Actually delete the page from _pageList - } - } - break; - case 'P' : // P - Set the page number. @todo Extend to multiple page selection - { - char* param=&(cmd[1]); // The page identity parameter - char* pageSet=_pageNumber;// The validated page identity - int matchedPages=-1; - if (Validate(pageSet, param)) - { - matchedPages=_pageList->Match(pageSet); - } - // pageSet is empty - if (matchedPages==0) - { - matchedPages=1; - status=8; - for (int i=0;i<5;i++) // Wildcards are not allowed here + case 0x0e: { - if (_pageNumber[i]=='*') - { - matchedPages=-1; // fail - } + strcpy(result,"This of course does not work. No CR in Softel \n\r"); + break; } - // @todo Create the page if status is 8 - if (status==8) + default: { - std::cerr << "[TCPClient::command] @todo Create the page" << std::endl; + sprintf(result,"Command not recognised cmd=%s\n\r",cmd); } - } - // Failed command - if (matchedPages<0) - { - matchedPages=0; - status=1; - } - _pageNumber[5]=0; // Terminate the page number before we print it just in case - std::cerr << "[TCPClient::command] _pageNumber=" << _pageNumber << std::endl; - sprintf(result,"%03d",matchedPages); - } - break; - case 'R' : // R - Read back row from the first selected page - { - TTXPageStream* p; - char rowStr[3]; - rowStr[0]=cmd[1]; - rowStr[1]=cmd[2]; - rowStr[2]=0; - row=std::strtol(rowStr, &ptr, 10); - p=_pageList->FirstPage(); - if (p==nullptr) - { - result[0]=0; - status=1; - } - else - { - TTXLine* line=p->GetRow(row); - strcpy(result,line->GetLine().c_str()); - } - } - break; - case 'T' :; - strcpy(result,"T not implemented\n\r"); - break; - case 'Y' : - snprintf(result,33,"VBIT620 Text Generator %s",VBIT2_VERSION); - break; - case 0x0e: - strcpy(result,"This of course does not work. No CR in Softel \n\r"); - break; - default: - sprintf(result,"Command not recognised cmd=%s\n\r",cmd); - } - sprintf(response,"%s%1d\n\r",result,status); + } + sprintf(response,"%s%1d\n\r",result,status); } // command void TCPClient::clearCmd(void) { - *_cmd=0; - _pCmd=_cmd; + *_cmd=0; + _pCmd=_cmd; } /** AddChar @@ -264,122 +266,140 @@ void TCPClient::clearCmd(void) */ void TCPClient::addChar(char ch, char* response) { - static int mode=MODENORMAL; - static int charCount=0; // Used to accumulate Newfor + static int mode=MODENORMAL; + static int charCount=0; // Used to accumulate Newfor std::stringstream ss; - response[0]=0; - switch (mode) - { - case MODENORMAL : - _pkt=_cmd; - if (_pCmd==_cmd) // On the first character we check if it is a Softel - { - switch (ch) - { - case 0x0e : - mode=MODESOFTELPAGEINIT; // page 0nnn - charCount=4; - break; - case 0x0f : - mode=MODEGETROWCOUNT; // n and n*(rowhigh, rowlow, 40 bytes) - break; - case 0x10 : - // Put the subtitle on air immediately - _newfor.SubtitleOnair(response); - clearCmd(); - mode=MODENORMAL; - return; - case 0x18 : - // Remove the subtitle immediately - _newfor.SubtitleOffair(); - strcpy(response, "[addChar]Clear"); - clearCmd(); - mode=MODENORMAL; - return; - } - } // If first character - if (ch!='\n' && ch!='\r') - { - *_pCmd++=ch; - *_pCmd=0; - if (response) response[0]=0; - } - else - { - // Got a complete non-newfor command - ss << "[TCPClient::addChar] finished cmd='" << strlen(_cmd) << "\n"; - std::cerr << ss.str(); - if (strlen(_cmd)) // Avoid this being called twice by \n\r combinations - { - command(_cmd, response); - } - clearCmd(); - mode=MODENORMAL; - } - break; - // Message type 1 - Set subtitle page. - 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 - *_pCmd++=ch; - charCount--; - // The last time around we have the completed command - if (!charCount) - { - int page=_newfor.SoftelPageInit(_cmd); - sprintf(response,"[addChar]MODESOFTELPAGEINIT Set page=%03x",page); - // Now that we are done, set up for the next command - clearCmd(); - mode=MODENORMAL; - } - break; - case MODEGETROWCOUNT: // Subtitle rows follow this - *_pCmd++=ch; - { - char* p=_cmd; - _row=_newfor.GetRowCount(p); - } - sprintf(response,"[TCPClient::addChar] MODEGETROWCOUNT =%d\n",_row); - mode=MODESUBTITLEDATAHIGHNYBBLE; - break; - case MODESUBTITLEDATAHIGHNYBBLE: - *_pCmd++=ch; - charCount=40; - mode=MODESUBTITLEDATALOWNYBBLE; - _rowAddress=vbi_unham8(ch)*16; // @todo Check validity - break; - case MODESUBTITLEDATALOWNYBBLE: - *_pCmd++=ch; - _rowAddress+=vbi_unham8(ch); // @todo Check validity - sprintf(response,"[addChar]MODESUBTITLEDATALOWNYBBLE _rowAddress=%d\n",_rowAddress); - mode=MODEGETROW; - _pkt=_pCmd; // Save the start of this packet - break; - case MODEGETROW: - *_pCmd++=ch; - *_pCmd=0; // cap off the string - charCount--; - if (charCount<=0) // End of line? - { - sprintf(response,"[TCPClient::addChar] MODEGETROW _rowAddress=%d _pkt=%s\n",_rowAddress,_pkt); - // Generate the teletext packet - _newfor.saveSubtitleRow(8,_rowAddress,_pkt); - if (_row>1) // Next row - { - _row--; - mode=MODESUBTITLEDATAHIGHNYBBLE; - } - else // Last row - { - // Now that we are done, set up for the next command - sprintf(response,"subtitle data complete\n"); - mode=MODENORMAL; - clearCmd(); - } - } - break; - } // State machine switch + response[0]=0; + switch (mode) + { + case MODENORMAL : + { + _pkt=_cmd; + if (_pCmd==_cmd) // On the first character we check if it is a Softel + { + switch (ch) + { + case 0x0e : + { + mode=MODESOFTELPAGEINIT; // page 0nnn + charCount=4; + break; + } + case 0x0f : + { + mode=MODEGETROWCOUNT; // n and n*(rowhigh, rowlow, 40 bytes) + break; + } + case 0x10 : + { + // Put the subtitle on air immediately + _newfor.SubtitleOnair(response); + clearCmd(); + mode=MODENORMAL; + return; + } + case 0x18 : + { + // Remove the subtitle immediately + _newfor.SubtitleOffair(); + strcpy(response, "[addChar]Clear"); + clearCmd(); + mode=MODENORMAL; + return; + } + } + } // If first character + if (ch!='\n' && ch!='\r') + { + *_pCmd++=ch; + *_pCmd=0; + if (response) response[0]=0; + } + else + { + // Got a complete non-newfor command + ss << "[TCPClient::addChar] finished cmd='" << strlen(_cmd) << "\n"; + std::cerr << ss.str(); + if (strlen(_cmd)) // Avoid this being called twice by \n\r combinations + { + command(_cmd, response); + } + clearCmd(); + mode=MODENORMAL; + } + break; + } + // Message type 1 - Set subtitle page. + 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 + *_pCmd++=ch; + charCount--; + // The last time around we have the completed command + if (!charCount) + { + int page=_newfor.SoftelPageInit(_cmd); + sprintf(response,"[addChar]MODESOFTELPAGEINIT Set page=%03x",page); + // Now that we are done, set up for the next command + clearCmd(); + mode=MODENORMAL; + } + break; + } + case MODEGETROWCOUNT: // Subtitle rows follow this + { + *_pCmd++=ch; + char* p=_cmd; + _row=_newfor.GetRowCount(p); + sprintf(response,"[TCPClient::addChar] MODEGETROWCOUNT =%d\n",_row); + mode=MODESUBTITLEDATAHIGHNYBBLE; + break; + } + case MODESUBTITLEDATAHIGHNYBBLE: + { + *_pCmd++=ch; + charCount=40; + mode=MODESUBTITLEDATALOWNYBBLE; + _rowAddress=vbi_unham8(ch)*16; // @todo Check validity + break; + } + case MODESUBTITLEDATALOWNYBBLE: + { + *_pCmd++=ch; + _rowAddress+=vbi_unham8(ch); // @todo Check validity + sprintf(response,"[addChar]MODESUBTITLEDATALOWNYBBLE _rowAddress=%d\n",_rowAddress); + mode=MODEGETROW; + _pkt=_pCmd; // Save the start of this packet + break; + } + case MODEGETROW: + { + *_pCmd++=ch; + *_pCmd=0; // cap off the string + charCount--; + if (charCount<=0) // End of line? + { + sprintf(response,"[TCPClient::addChar] MODEGETROW _rowAddress=%d _pkt=%s\n",_rowAddress,_pkt); + // Generate the teletext packet + _newfor.saveSubtitleRow(8,_rowAddress,_pkt); + if (_row>1) // Next row + { + _row--; + mode=MODESUBTITLEDATAHIGHNYBBLE; + } + else // Last row + { + // Now that we are done, set up for the next command + sprintf(response,"subtitle data complete\n"); + mode=MODENORMAL; + clearCmd(); + } + } + break; + } + } // State machine switch } @@ -389,32 +409,33 @@ void TCPClient::addChar(char ch, char* response) */ void TCPClient::Handler(int clntSocket) { - char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */ - char response[RCVBUFSIZE]; - int recvMsgSize; /* Size of received message */ - int i; - clearCmd(); + char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */ + char response[RCVBUFSIZE]; + int recvMsgSize; /* Size of received message */ + int i; + clearCmd(); - /* Send received string and receive again until end of transmission */ - for (recvMsgSize=1;recvMsgSize > 0;) /* zero indicates end of transmission */ - { - /* See if there is more data to receive */ - if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) - DieWithError("recv() failed"); - for (i=0;i 0;) /* zero indicates end of transmission */ + { + /* See if there is more data to receive */ + if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) + DieWithError("recv() failed"); + for (i=0;i'8') && - (ch!='*')) - { - valid=false; - } - break; - case 1: // pp - page number - case 2: - // Change case? - if (ch>='a' && ch<='f') - { - ch-='a'-'A'; - } - if ((ch<'0' || ch>'9') && - (ch<'A' || ch>'F') && - (ch!='*')) + // Get the next input character and validate it + char ch=*src++; + // If we hit a null, pad with 0 to the end and stay valid + if (pad || ch==0) { - valid=false; + pad=true; + ch='0'; } - /* fallthrough */ - case 3: // aa - internal subpage (related to subcode but NOT the same thing) - case 4: - if ((ch<'0' || ch>'9') && - (ch!='*')) + else { - valid=false; + switch (i) + { + case 0: // m - magazine + { + if ((ch<'1' || ch>'8') && (ch!='*')) + { + valid=false; + } + break; + } + case 1: // pp - page number + case 2: + { + // Change case? + if (ch>='a' && ch<='f') + { + ch-='a'-'A'; + } + if ((ch<'0' || ch>'9') && (ch<'A' || ch>'F') && (ch!='*')) + { + valid=false; + } + // fallthrough + [[gnu::fallthrough]]; + } + case 3: // aa - internal subpage (related to subcode but NOT the same thing) + case 4: + { + if ((ch<'0' || ch>'9') && (ch!='*')) + { + valid=false; + } + } + } // switch } - } // switch - - } - *dest++=ch; - } // for each character - return valid; + *dest++=ch; + } // for each character + return valid; } diff --git a/TCPClient.h b/TCPClient.h index 67dc1b2..7f173ba 100644 --- a/TCPClient.h +++ b/TCPClient.h @@ -52,76 +52,71 @@ #include "pagelist.h" #include "newfor.h" -#include "hamm-tables.h" #include "packetsubtitle.h" namespace vbit { - -class TCPClient -{ -public: - TCPClient(PacketSubtitle* subtitle, ttx::PageList* pageList); - ~TCPClient(); - void Handler(int clntSocket); - -private: - // Constants - static const uint8_t MAXCMD=128; - static const uint8_t RCVBUFSIZE=132; /* Size of receive buffer */ - -// Normal command mode - static const uint8_t MODENORMAL=0; - static const uint8_t MODESOFTELPAGEINIT=1; -// Get row count - static const uint8_t MODEGETROWCOUNT=3; -// Get a row of data - static const uint8_t MODEGETROW=4; -// Display the row - static const uint8_t MODESUBTITLEONAIR=5; -// Clear down - static const uint8_t MODESUBTITLEOFFAIR=6; - static const uint8_t MODESUBTITLEDATAHIGHNYBBLE=7; - static const uint8_t MODESUBTITLEDATALOWNYBBLE=8; - - // Variables - char _cmd[MAXCMD]; /// command buffer - char* _pCmd; /// Pointer into the command buffer - Newfor _newfor; - int _row; // Row counter - char* _pkt; // A teletext packet (one row of VBI) - int _rowAddress; // The address of this row - - /// The page address in MPPSS (hex. 10000..8FF99. Omitting trailing characters defaults to 0 - /// * wildcard - char _pageNumber[6]; - - ttx::PageList* _pageList; /// List of pages for XTP620 commands to access - - - // Functions - void clearCmd(void); - void addChar(char ch, char* response); - void command(char* cmd, char* response); /// Handles XPT620 commands - void DieWithError(std::string errorMessage); - - /** Validate a page identity of the form mppss - * Where: - * m=1..8 - * p=0..f - * s=0,,9 - * and any digit can be wildcarded with * - * and trailing digits can be omitted where they will be defaulted to 0 - * \param src - the page identity parameter of a P command. (only one allowed in this implementation) - * \param dest - the validated page number - * \return true if the page identity is valid - */ - bool Validate(char* dest, char* src); - -}; // TCPClient - -} // End of namespace vbit - - + class TCPClient + { + public: + TCPClient(PacketSubtitle* subtitle, ttx::PageList* pageList); + ~TCPClient(); + void Handler(int clntSocket); + + private: + // Constants + static const uint8_t MAXCMD=128; + static const uint8_t RCVBUFSIZE=132; /* Size of receive buffer */ + + // Normal command mode + static const uint8_t MODENORMAL=0; + static const uint8_t MODESOFTELPAGEINIT=1; + // Get row count + static const uint8_t MODEGETROWCOUNT=3; + // Get a row of data + static const uint8_t MODEGETROW=4; + // Display the row + static const uint8_t MODESUBTITLEONAIR=5; + // Clear down + static const uint8_t MODESUBTITLEOFFAIR=6; + static const uint8_t MODESUBTITLEDATAHIGHNYBBLE=7; + static const uint8_t MODESUBTITLEDATALOWNYBBLE=8; + + // Variables + char _cmd[MAXCMD]; // command buffer + char* _pCmd; // Pointer into the command buffer + Newfor _newfor; + int _row; // Row counter + char* _pkt; // A teletext packet (one row of VBI) + int _rowAddress; // The address of this row + + /** The page address in MPPSS (hex. 10000..8FF99. Omitting trailing characters defaults to 0 + * wildcard + */ + char _pageNumber[6]; + + ttx::PageList* _pageList; // List of pages for XTP620 commands to access + + + // Functions + void clearCmd(void); + void addChar(char ch, char* response); + void command(char* cmd, char* response); // Handles XPT620 commands + void DieWithError(std::string errorMessage); + + /** Validate a page identity of the form mppss + * Where: + * m=1..8 + * p=0..f + * s=0,,9 + * and any digit can be wildcarded with * + * and trailing digits can be omitted where they will be defaulted to 0 + * \param src - the page identity parameter of a P command. (only one allowed in this implementation) + * \param dest - the validated page number + * \return true if the page identity is valid + */ + bool Validate(char* dest, char* src); + }; +} #endif diff --git a/command.cpp b/command.cpp index 48dd504..b440abd 100644 --- a/command.cpp +++ b/command.cpp @@ -34,11 +34,11 @@ using namespace vbit; using namespace ttx; Command::Command(Configure *configure, PacketSubtitle* subtitle=nullptr, PageList *pageList=nullptr) : - _portNumber(configure->GetCommandPort()), - _client(subtitle, pageList) + _portNumber(configure->GetCommandPort()), + _client(subtitle, pageList) { // Constructor - // Start a listener thread + // Start a listener thread } Command::~Command() @@ -69,7 +69,8 @@ void Command::run() // Initialize Winsock iResult = WSAStartup(MAKEWORD(2,2), &wsaData); - if (iResult != 0) { + if (iResult != 0) + { DieWithError("WSAStartup failed"); } #else @@ -87,11 +88,11 @@ 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"); + DieWithError("bind() failed"); /* Mark the socket so it will listen for incoming connections */ if (listen(serverSock, MAXPENDING) < 0) diff --git a/command.h b/command.h index e84982a..f3d7607 100644 --- a/command.h +++ b/command.h @@ -56,48 +56,38 @@ namespace vbit { - -class Command -{ - public: - - /** - * @brief Constructor - * @description Listens on port 5570 and accepts connections. - * When connected it can be sent Newfor commands. - */ - Command(ttx::Configure *configure, vbit::PacketSubtitle* subtitle, ttx::PageList* pageList); - - /** - * @brief Constructor - * @param port - TCP port number to use - */ - // Command(int port); - - /** - * @brief Destructor - */ - ~Command(); - - /** - * @brief Run the listener thread. - */ - void run(); - - private: - int _portNumber; /// The port number is configurable. Default is 5570 for no oarticular reason. - TCPClient _client; /// Did I call this a client? It is where clients connect and get their commands executed. - - /* Page init and subtitle data can respond with these 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 */ - - void DieWithError(std::string errorMessage); /* Error handling function */ - - -}; // Command -} // namespace vbit + class Command + { + public: + /** + * @brief Constructor + * @description Listens on port 5570 and accepts connections. + * When connected it can be sent Newfor commands. + */ + Command(ttx::Configure *configure, vbit::PacketSubtitle* subtitle, ttx::PageList* pageList); + + /** + * @brief Destructor + */ + ~Command(); + + /** + * @brief Run the listener thread. + */ + void run(); + + private: + int _portNumber; /// The port number is configurable. Default is 5570 for no oarticular reason. + TCPClient _client; /// Did I call this a client? It is where clients connect and get their commands executed. + + /* Page init and subtitle data can respond with these 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 */ + + void DieWithError(std::string errorMessage); /* Error handling function */ + }; +} #endif diff --git a/configure.cpp b/configure.cpp index 87c6a5e..e62c5bc 100644 --- a/configure.cpp +++ b/configure.cpp @@ -4,7 +4,8 @@ using namespace ttx; -int Configure::DirExists(char *path){ +int Configure::DirExists(char *path) +{ struct stat info; if(stat(path, &info ) != 0) @@ -111,7 +112,8 @@ int Configure::LoadConfigFile(std::string filename) // these are all the valid strings for config lines std::vector nameStrings{ "header_template", "initial_teletext_page", "row_adaptive_mode", "network_identification_code", "country_network_identification", "full_field", "status_display", "subtitle_repeats","enable_command_port","command_port","lines_per_field","magazine_priority" }; - if (filein.is_open()){ + if (filein.is_open()) + { ss << "[Configure::LoadConfigFile] opened " << filename << "\n"; std::cerr << ss.str(); @@ -119,52 +121,70 @@ int Configure::LoadConfigFile(std::string filename) std::string name; std::string value; TTXLine* header = new TTXLine(); - while (std::getline(filein >> std::ws, line)){ - if (line.front() != ';'){ // ignore comments + while (std::getline(filein >> std::ws, line)) + { + if (line.front() != ';') // ignore comments + { std::size_t delim = line.find("=", 0); int error = 0; - if (delim != std::string::npos){ + if (delim != std::string::npos) + { name = line.substr(0, delim); value = line.substr(delim + 1); iter = find(nameStrings.begin(), nameStrings.end(), name); - if(iter != nameStrings.end()){ + if(iter != nameStrings.end()) + { // matched string - switch(iter - nameStrings.begin()){ + switch(iter - nameStrings.begin()) + { case 0: // header_template + { header->Setm_textline(value,true); value = header->GetLine(); value.resize(32,' '); _headerTemplate.assign(value); break; - + } case 1: // initial_teletext_page - if (value.size() >= 3){ + { + if (value.size() >= 3) + { size_t idx; int magpage; int subcode; - try { + try + { magpage = stoi(std::string(value, 0, 3), &idx, 16); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - if (magpage < 0x100 || magpage > 0x8FF || (magpage & 0xFF) == 0xFF){ + if (magpage < 0x100 || magpage > 0x8FF || (magpage & 0xFF) == 0xFF) + { error = 1; break; } - if (value.size() > 3){ - if ((value.size() != 8) || (value.at(idx) != ':')){ + if (value.size() > 3) + { + if ((value.size() != 8) || (value.at(idx) != ':')) + { error = 1; break; } - try { + try + { subcode = stoi(std::string(value, 4, 4), &idx, 16); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - if (subcode < 0x0000 || subcode > 0x3F7F || subcode & 0xC080){ + if (subcode < 0x0000 || subcode > 0x3F7F || subcode & 0xC080) + { error = 1; break; } @@ -176,94 +196,153 @@ int Configure::LoadConfigFile(std::string filename) } error = 1; break; - + } case 2: // row_adaptive_mode - if (!value.compare("true")){ + { + if (!value.compare("true")) + { _rowAdaptive = true; - } else if (!value.compare("false")){ + } + else if (!value.compare("false")) + { _rowAdaptive = false; - } else { + } + else + { error = 1; } break; + } case 3: // "network_identification_code" - four character hex. eg. FA6F - if (value.size() == 4){ + { + if (value.size() == 4) + { size_t idx; - try { + try + { _NetworkIdentificationCode = stoi(std::string(value, 0, 4), &idx, 16); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - } else { + } + else + { error = 1; } break; + } case 4: // "country_network_identification" - four character hex. eg. 2C2F - if (value.size() == 4){ + { + if (value.size() == 4) + { size_t idx; - try { + try + { _CountryNetworkIdentificationCode = stoi(std::string(value, 0, 4), &idx, 16); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - } else { + } + else + { error = 1; } break; + } case 5: // "full_field" + { break; + } case 6: // "status_display" + { value.resize(20,' '); // string must be 20 characters _serviceStatusString.assign(value); break; + } case 7: // "subtitle_repeats" - The number of times a subtitle transmission is repeated 0..9 - if (value.size() == 1){ - try { + { + if (value.size() == 1) + { + try + { _subtitleRepeats = stoi(std::string(value, 0, 1)); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - } else { + } + else + { error = 1; } break; + } case 8: // "enable_command_port" - if (!value.compare("true")){ + { + if (!value.compare("true")) + { _commandPortEnabled = true; - } else if (!value.compare("false")){ + } + else if (!value.compare("false")) + { _commandPortEnabled = false; - } else { + } + else + { error = 1; } break; + } case 9: // "command_port" - if (value.size() > 0 && value.size() < 6){ - try { + { + if (value.size() > 0 && value.size() < 6) + { + try + { _commandPort = stoi(std::string(value, 0, 5)); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - } else { + } + else + { error = 1; } break; + } case 10: // "lines_per_field" - if (value.size() > 0 && value.size() < 4){ - try { + { + if (value.size() > 0 && value.size() < 4) + { + try + { _linesPerField = stoi(std::string(value, 0, 3)); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } - } else { + } + else + { error = 1; } break; + } case 11: // "magazine_priority" + { std::stringstream ss(value); std::string temps; int tmp[8]; @@ -272,9 +351,12 @@ int Configure::LoadConfigFile(std::string filename) { if (std::getline(ss, temps, ',')) { - try { + try + { tmp[i] = stoi(temps); - } catch (const std::invalid_argument& ia) { + } + catch (const std::invalid_argument& ia) + { error = 1; break; } @@ -293,8 +375,11 @@ int Configure::LoadConfigFile(std::string filename) for (i=0; i<8; i++) _magazinePriority[i] = tmp[i]; break; + } } - } else { + } + else + { error = 1; // unrecognised config line } } @@ -307,7 +392,9 @@ int Configure::LoadConfigFile(std::string filename) } filein.close(); return 0; - } else { + } + else + { std::cerr << "[Configure::LoadConfigFile] open failed\n"; return -1; } diff --git a/configure.h b/configure.h index f55c9df..ecc2312 100644 --- a/configure.h +++ b/configure.h @@ -69,7 +69,7 @@ class Configure uint16_t _linesPerField; // settings for generation of packet 8/30 - bool _multiplexedSignalFlag; // false indicates teletext is multiplexed with video, true means full frame teletext. + bool _multiplexedSignalFlag; // false indicates teletext is multiplexed with video, true means full frame teletext. int _magazinePriority[8]; uint8_t _initialMag; uint8_t _initialPage; diff --git a/filemonitor.cpp b/filemonitor.cpp index 4aeb041..8693a4a 100644 --- a/filemonitor.cpp +++ b/filemonitor.cpp @@ -28,20 +28,20 @@ using namespace vbit; using namespace ttx; FileMonitor::FileMonitor(Configure *configure, PageList *pageList) : - _configure(configure),_pageList(pageList) + _configure(configure),_pageList(pageList) { - //ctor + //ctor } FileMonitor::FileMonitor() - : _pageList(nullptr) + : _pageList(nullptr) { - //ctor + //ctor } FileMonitor::~FileMonitor() { - //dtor + //dtor } void FileMonitor::run() @@ -72,7 +72,8 @@ void FileMonitor::run() } } // run -int FileMonitor::readDirectory(std::string path){ +int FileMonitor::readDirectory(std::string path) +{ struct dirent *dirp; struct stat attrib; diff --git a/filemonitor.h b/filemonitor.h index 0857515..8eb8df3 100644 --- a/filemonitor.h +++ b/filemonitor.h @@ -18,30 +18,28 @@ namespace vbit { - -class FileMonitor -{ - public: - /** Default constructor */ - FileMonitor(); - FileMonitor(ttx::Configure *configure, ttx::PageList *pageList); - /** Default destructor */ - virtual ~FileMonitor(); - - /** - * Runs the monitoring thread and does not terminate (at least for now) - * @return Nothing useful yet. Perhaps return an error status if something goes wrong - */ - void run(); - - protected: - - private: - ttx::Configure* _configure; /// Member reference to the configuration settings - ttx::PageList* _pageList; - int readDirectory(std::string path); -}; - + class FileMonitor + { + public: + /** Default constructor */ + FileMonitor(); + FileMonitor(ttx::Configure *configure, ttx::PageList *pageList); + /** Default destructor */ + virtual ~FileMonitor(); + + /** + * Runs the monitoring thread and does not terminate (at least for now) + * @return Nothing useful yet. Perhaps return an error status if something goes wrong + */ + void run(); + + protected: + + private: + ttx::Configure* _configure; /// Member reference to the configuration settings + ttx::PageList* _pageList; + int readDirectory(std::string path); + }; } #endif // _FILEMONITOR_H_ diff --git a/hamm-tables.h b/hamm-tables.h deleted file mode 100644 index 38efd35..0000000 --- a/hamm-tables.h +++ /dev/null @@ -1,309 +0,0 @@ -#ifndef _HAMM_TABLES_H_ -#define _HAMM_TABLES_H_ -/* This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301 USA. */ - -const uint8_t -_vbi_bit_reverse [256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -const uint8_t -_vbi_hamm8_fwd [16] = { - 0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f, - 0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea -}; - -const uint8_t -_vbi_hamm8_inv [256] = { - 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff, - 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, - 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00, - 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, - 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, - 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07, - 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, - 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, - 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, - 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, - 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, - 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, - 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff, - 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, - 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05, - 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, - 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, - 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff, - 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, - 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b, - 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, - 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, - 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d, - 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, - 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09, - 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, - 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, - 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, - 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, - 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, - 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, - 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e -}; - -static const uint8_t -_vbi_hamm24_fwd_0 [256] = { - 0x8b, 0x8c, 0x92, 0x95, 0xa1, 0xa6, 0xb8, 0xbf, - 0xc0, 0xc7, 0xd9, 0xde, 0xea, 0xed, 0xf3, 0xf4, - 0x0a, 0x0d, 0x13, 0x14, 0x20, 0x27, 0x39, 0x3e, - 0x41, 0x46, 0x58, 0x5f, 0x6b, 0x6c, 0x72, 0x75, - 0x09, 0x0e, 0x10, 0x17, 0x23, 0x24, 0x3a, 0x3d, - 0x42, 0x45, 0x5b, 0x5c, 0x68, 0x6f, 0x71, 0x76, - 0x88, 0x8f, 0x91, 0x96, 0xa2, 0xa5, 0xbb, 0xbc, - 0xc3, 0xc4, 0xda, 0xdd, 0xe9, 0xee, 0xf0, 0xf7, - 0x08, 0x0f, 0x11, 0x16, 0x22, 0x25, 0x3b, 0x3c, - 0x43, 0x44, 0x5a, 0x5d, 0x69, 0x6e, 0x70, 0x77, - 0x89, 0x8e, 0x90, 0x97, 0xa3, 0xa4, 0xba, 0xbd, - 0xc2, 0xc5, 0xdb, 0xdc, 0xe8, 0xef, 0xf1, 0xf6, - 0x8a, 0x8d, 0x93, 0x94, 0xa0, 0xa7, 0xb9, 0xbe, - 0xc1, 0xc6, 0xd8, 0xdf, 0xeb, 0xec, 0xf2, 0xf5, - 0x0b, 0x0c, 0x12, 0x15, 0x21, 0x26, 0x38, 0x3f, - 0x40, 0x47, 0x59, 0x5e, 0x6a, 0x6d, 0x73, 0x74, - 0x03, 0x04, 0x1a, 0x1d, 0x29, 0x2e, 0x30, 0x37, - 0x48, 0x4f, 0x51, 0x56, 0x62, 0x65, 0x7b, 0x7c, - 0x82, 0x85, 0x9b, 0x9c, 0xa8, 0xaf, 0xb1, 0xb6, - 0xc9, 0xce, 0xd0, 0xd7, 0xe3, 0xe4, 0xfa, 0xfd, - 0x81, 0x86, 0x98, 0x9f, 0xab, 0xac, 0xb2, 0xb5, - 0xca, 0xcd, 0xd3, 0xd4, 0xe0, 0xe7, 0xf9, 0xfe, - 0x00, 0x07, 0x19, 0x1e, 0x2a, 0x2d, 0x33, 0x34, - 0x4b, 0x4c, 0x52, 0x55, 0x61, 0x66, 0x78, 0x7f, - 0x80, 0x87, 0x99, 0x9e, 0xaa, 0xad, 0xb3, 0xb4, - 0xcb, 0xcc, 0xd2, 0xd5, 0xe1, 0xe6, 0xf8, 0xff, - 0x01, 0x06, 0x18, 0x1f, 0x2b, 0x2c, 0x32, 0x35, - 0x4a, 0x4d, 0x53, 0x54, 0x60, 0x67, 0x79, 0x7e, - 0x02, 0x05, 0x1b, 0x1c, 0x28, 0x2f, 0x31, 0x36, - 0x49, 0x4e, 0x50, 0x57, 0x63, 0x64, 0x7a, 0x7d, - 0x83, 0x84, 0x9a, 0x9d, 0xa9, 0xae, 0xb0, 0xb7, - 0xc8, 0xcf, 0xd1, 0xd6, 0xe2, 0xe5, 0xfb, 0xfc -}; - -static const uint8_t -_vbi_hamm24_fwd_1 [256] = { - 0x00, 0x89, 0x8a, 0x03, 0x8b, 0x02, 0x01, 0x88, - 0x01, 0x88, 0x8b, 0x02, 0x8a, 0x03, 0x00, 0x89, - 0x02, 0x8b, 0x88, 0x01, 0x89, 0x00, 0x03, 0x8a, - 0x03, 0x8a, 0x89, 0x00, 0x88, 0x01, 0x02, 0x8b, - 0x03, 0x8a, 0x89, 0x00, 0x88, 0x01, 0x02, 0x8b, - 0x02, 0x8b, 0x88, 0x01, 0x89, 0x00, 0x03, 0x8a, - 0x01, 0x88, 0x8b, 0x02, 0x8a, 0x03, 0x00, 0x89, - 0x00, 0x89, 0x8a, 0x03, 0x8b, 0x02, 0x01, 0x88, - 0x08, 0x81, 0x82, 0x0b, 0x83, 0x0a, 0x09, 0x80, - 0x09, 0x80, 0x83, 0x0a, 0x82, 0x0b, 0x08, 0x81, - 0x0a, 0x83, 0x80, 0x09, 0x81, 0x08, 0x0b, 0x82, - 0x0b, 0x82, 0x81, 0x08, 0x80, 0x09, 0x0a, 0x83, - 0x0b, 0x82, 0x81, 0x08, 0x80, 0x09, 0x0a, 0x83, - 0x0a, 0x83, 0x80, 0x09, 0x81, 0x08, 0x0b, 0x82, - 0x09, 0x80, 0x83, 0x0a, 0x82, 0x0b, 0x08, 0x81, - 0x08, 0x81, 0x82, 0x0b, 0x83, 0x0a, 0x09, 0x80, - 0x09, 0x80, 0x83, 0x0a, 0x82, 0x0b, 0x08, 0x81, - 0x08, 0x81, 0x82, 0x0b, 0x83, 0x0a, 0x09, 0x80, - 0x0b, 0x82, 0x81, 0x08, 0x80, 0x09, 0x0a, 0x83, - 0x0a, 0x83, 0x80, 0x09, 0x81, 0x08, 0x0b, 0x82, - 0x0a, 0x83, 0x80, 0x09, 0x81, 0x08, 0x0b, 0x82, - 0x0b, 0x82, 0x81, 0x08, 0x80, 0x09, 0x0a, 0x83, - 0x08, 0x81, 0x82, 0x0b, 0x83, 0x0a, 0x09, 0x80, - 0x09, 0x80, 0x83, 0x0a, 0x82, 0x0b, 0x08, 0x81, - 0x01, 0x88, 0x8b, 0x02, 0x8a, 0x03, 0x00, 0x89, - 0x00, 0x89, 0x8a, 0x03, 0x8b, 0x02, 0x01, 0x88, - 0x03, 0x8a, 0x89, 0x00, 0x88, 0x01, 0x02, 0x8b, - 0x02, 0x8b, 0x88, 0x01, 0x89, 0x00, 0x03, 0x8a, - 0x02, 0x8b, 0x88, 0x01, 0x89, 0x00, 0x03, 0x8a, - 0x03, 0x8a, 0x89, 0x00, 0x88, 0x01, 0x02, 0x8b, - 0x00, 0x89, 0x8a, 0x03, 0x8b, 0x02, 0x01, 0x88, - 0x01, 0x88, 0x8b, 0x02, 0x8a, 0x03, 0x00, 0x89 -}; - -static const uint8_t -_vbi_hamm24_fwd_2 [4] = { - 0x00, 0x0a, 0x0b, 0x01 -}; - -const int8_t -_vbi_hamm24_inv_par [3][256] = { - { - 0x00, 0x21, 0x22, 0x03, 0x23, 0x02, 0x01, 0x20, - 0x24, 0x05, 0x06, 0x27, 0x07, 0x26, 0x25, 0x04, - 0x25, 0x04, 0x07, 0x26, 0x06, 0x27, 0x24, 0x05, - 0x01, 0x20, 0x23, 0x02, 0x22, 0x03, 0x00, 0x21, - 0x26, 0x07, 0x04, 0x25, 0x05, 0x24, 0x27, 0x06, - 0x02, 0x23, 0x20, 0x01, 0x21, 0x00, 0x03, 0x22, - 0x03, 0x22, 0x21, 0x00, 0x20, 0x01, 0x02, 0x23, - 0x27, 0x06, 0x05, 0x24, 0x04, 0x25, 0x26, 0x07, - 0x27, 0x06, 0x05, 0x24, 0x04, 0x25, 0x26, 0x07, - 0x03, 0x22, 0x21, 0x00, 0x20, 0x01, 0x02, 0x23, - 0x02, 0x23, 0x20, 0x01, 0x21, 0x00, 0x03, 0x22, - 0x26, 0x07, 0x04, 0x25, 0x05, 0x24, 0x27, 0x06, - 0x01, 0x20, 0x23, 0x02, 0x22, 0x03, 0x00, 0x21, - 0x25, 0x04, 0x07, 0x26, 0x06, 0x27, 0x24, 0x05, - 0x24, 0x05, 0x06, 0x27, 0x07, 0x26, 0x25, 0x04, - 0x00, 0x21, 0x22, 0x03, 0x23, 0x02, 0x01, 0x20, - 0x28, 0x09, 0x0a, 0x2b, 0x0b, 0x2a, 0x29, 0x08, - 0x0c, 0x2d, 0x2e, 0x0f, 0x2f, 0x0e, 0x0d, 0x2c, - 0x0d, 0x2c, 0x2f, 0x0e, 0x2e, 0x0f, 0x0c, 0x2d, - 0x29, 0x08, 0x0b, 0x2a, 0x0a, 0x2b, 0x28, 0x09, - 0x0e, 0x2f, 0x2c, 0x0d, 0x2d, 0x0c, 0x0f, 0x2e, - 0x2a, 0x0b, 0x08, 0x29, 0x09, 0x28, 0x2b, 0x0a, - 0x2b, 0x0a, 0x09, 0x28, 0x08, 0x29, 0x2a, 0x0b, - 0x0f, 0x2e, 0x2d, 0x0c, 0x2c, 0x0d, 0x0e, 0x2f, - 0x0f, 0x2e, 0x2d, 0x0c, 0x2c, 0x0d, 0x0e, 0x2f, - 0x2b, 0x0a, 0x09, 0x28, 0x08, 0x29, 0x2a, 0x0b, - 0x2a, 0x0b, 0x08, 0x29, 0x09, 0x28, 0x2b, 0x0a, - 0x0e, 0x2f, 0x2c, 0x0d, 0x2d, 0x0c, 0x0f, 0x2e, - 0x29, 0x08, 0x0b, 0x2a, 0x0a, 0x2b, 0x28, 0x09, - 0x0d, 0x2c, 0x2f, 0x0e, 0x2e, 0x0f, 0x0c, 0x2d, - 0x0c, 0x2d, 0x2e, 0x0f, 0x2f, 0x0e, 0x0d, 0x2c, - 0x28, 0x09, 0x0a, 0x2b, 0x0b, 0x2a, 0x29, 0x08 - }, { - 0x00, 0x29, 0x2a, 0x03, 0x2b, 0x02, 0x01, 0x28, - 0x2c, 0x05, 0x06, 0x2f, 0x07, 0x2e, 0x2d, 0x04, - 0x2d, 0x04, 0x07, 0x2e, 0x06, 0x2f, 0x2c, 0x05, - 0x01, 0x28, 0x2b, 0x02, 0x2a, 0x03, 0x00, 0x29, - 0x2e, 0x07, 0x04, 0x2d, 0x05, 0x2c, 0x2f, 0x06, - 0x02, 0x2b, 0x28, 0x01, 0x29, 0x00, 0x03, 0x2a, - 0x03, 0x2a, 0x29, 0x00, 0x28, 0x01, 0x02, 0x2b, - 0x2f, 0x06, 0x05, 0x2c, 0x04, 0x2d, 0x2e, 0x07, - 0x2f, 0x06, 0x05, 0x2c, 0x04, 0x2d, 0x2e, 0x07, - 0x03, 0x2a, 0x29, 0x00, 0x28, 0x01, 0x02, 0x2b, - 0x02, 0x2b, 0x28, 0x01, 0x29, 0x00, 0x03, 0x2a, - 0x2e, 0x07, 0x04, 0x2d, 0x05, 0x2c, 0x2f, 0x06, - 0x01, 0x28, 0x2b, 0x02, 0x2a, 0x03, 0x00, 0x29, - 0x2d, 0x04, 0x07, 0x2e, 0x06, 0x2f, 0x2c, 0x05, - 0x2c, 0x05, 0x06, 0x2f, 0x07, 0x2e, 0x2d, 0x04, - 0x00, 0x29, 0x2a, 0x03, 0x2b, 0x02, 0x01, 0x28, - 0x30, 0x19, 0x1a, 0x33, 0x1b, 0x32, 0x31, 0x18, - 0x1c, 0x35, 0x36, 0x1f, 0x37, 0x1e, 0x1d, 0x34, - 0x1d, 0x34, 0x37, 0x1e, 0x36, 0x1f, 0x1c, 0x35, - 0x31, 0x18, 0x1b, 0x32, 0x1a, 0x33, 0x30, 0x19, - 0x1e, 0x37, 0x34, 0x1d, 0x35, 0x1c, 0x1f, 0x36, - 0x32, 0x1b, 0x18, 0x31, 0x19, 0x30, 0x33, 0x1a, - 0x33, 0x1a, 0x19, 0x30, 0x18, 0x31, 0x32, 0x1b, - 0x1f, 0x36, 0x35, 0x1c, 0x34, 0x1d, 0x1e, 0x37, - 0x1f, 0x36, 0x35, 0x1c, 0x34, 0x1d, 0x1e, 0x37, - 0x33, 0x1a, 0x19, 0x30, 0x18, 0x31, 0x32, 0x1b, - 0x32, 0x1b, 0x18, 0x31, 0x19, 0x30, 0x33, 0x1a, - 0x1e, 0x37, 0x34, 0x1d, 0x35, 0x1c, 0x1f, 0x36, - 0x31, 0x18, 0x1b, 0x32, 0x1a, 0x33, 0x30, 0x19, - 0x1d, 0x34, 0x37, 0x1e, 0x36, 0x1f, 0x1c, 0x35, - 0x1c, 0x35, 0x36, 0x1f, 0x37, 0x1e, 0x1d, 0x34, - 0x30, 0x19, 0x1a, 0x33, 0x1b, 0x32, 0x31, 0x18 - }, { - 0x3f, 0x0e, 0x0d, 0x3c, 0x0c, 0x3d, 0x3e, 0x0f, - 0x0b, 0x3a, 0x39, 0x08, 0x38, 0x09, 0x0a, 0x3b, - 0x0a, 0x3b, 0x38, 0x09, 0x39, 0x08, 0x0b, 0x3a, - 0x3e, 0x0f, 0x0c, 0x3d, 0x0d, 0x3c, 0x3f, 0x0e, - 0x09, 0x38, 0x3b, 0x0a, 0x3a, 0x0b, 0x08, 0x39, - 0x3d, 0x0c, 0x0f, 0x3e, 0x0e, 0x3f, 0x3c, 0x0d, - 0x3c, 0x0d, 0x0e, 0x3f, 0x0f, 0x3e, 0x3d, 0x0c, - 0x08, 0x39, 0x3a, 0x0b, 0x3b, 0x0a, 0x09, 0x38, - 0x08, 0x39, 0x3a, 0x0b, 0x3b, 0x0a, 0x09, 0x38, - 0x3c, 0x0d, 0x0e, 0x3f, 0x0f, 0x3e, 0x3d, 0x0c, - 0x3d, 0x0c, 0x0f, 0x3e, 0x0e, 0x3f, 0x3c, 0x0d, - 0x09, 0x38, 0x3b, 0x0a, 0x3a, 0x0b, 0x08, 0x39, - 0x3e, 0x0f, 0x0c, 0x3d, 0x0d, 0x3c, 0x3f, 0x0e, - 0x0a, 0x3b, 0x38, 0x09, 0x39, 0x08, 0x0b, 0x3a, - 0x0b, 0x3a, 0x39, 0x08, 0x38, 0x09, 0x0a, 0x3b, - 0x3f, 0x0e, 0x0d, 0x3c, 0x0c, 0x3d, 0x3e, 0x0f, - 0x1f, 0x2e, 0x2d, 0x1c, 0x2c, 0x1d, 0x1e, 0x2f, - 0x2b, 0x1a, 0x19, 0x28, 0x18, 0x29, 0x2a, 0x1b, - 0x2a, 0x1b, 0x18, 0x29, 0x19, 0x28, 0x2b, 0x1a, - 0x1e, 0x2f, 0x2c, 0x1d, 0x2d, 0x1c, 0x1f, 0x2e, - 0x29, 0x18, 0x1b, 0x2a, 0x1a, 0x2b, 0x28, 0x19, - 0x1d, 0x2c, 0x2f, 0x1e, 0x2e, 0x1f, 0x1c, 0x2d, - 0x1c, 0x2d, 0x2e, 0x1f, 0x2f, 0x1e, 0x1d, 0x2c, - 0x28, 0x19, 0x1a, 0x2b, 0x1b, 0x2a, 0x29, 0x18, - 0x28, 0x19, 0x1a, 0x2b, 0x1b, 0x2a, 0x29, 0x18, - 0x1c, 0x2d, 0x2e, 0x1f, 0x2f, 0x1e, 0x1d, 0x2c, - 0x1d, 0x2c, 0x2f, 0x1e, 0x2e, 0x1f, 0x1c, 0x2d, - 0x29, 0x18, 0x1b, 0x2a, 0x1a, 0x2b, 0x28, 0x19, - 0x1e, 0x2f, 0x2c, 0x1d, 0x2d, 0x1c, 0x1f, 0x2e, - 0x2a, 0x1b, 0x18, 0x29, 0x19, 0x28, 0x2b, 0x1a, - 0x2b, 0x1a, 0x19, 0x28, 0x18, 0x29, 0x2a, 0x1b, - 0x1f, 0x2e, 0x2d, 0x1c, 0x2c, 0x1d, 0x1e, 0x2f - } -}; - -static const uint8_t -_vbi_hamm24_inv_d1_d4 [64] = { - 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, - 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, - 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, - 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, - 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, - 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f -}; - -static const uint32_t -_vbi_hamm24_inv_err [64] = { - 0x00000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000001, - 0x00000000, 0x00000002, 0x00000004, 0x00000008, - 0x00000000, 0x00000010, 0x00000020, 0x00000040, - 0x00000080, 0x00000100, 0x00000200, 0x00000400, - 0x00000000, 0x00000800, 0x00001000, 0x00002000, - 0x00004000, 0x00008000, 0x00010000, 0x00020000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000 -}; - -#endif diff --git a/newfor.cpp b/newfor.cpp index 2b88d63..8141398 100644 --- a/newfor.cpp +++ b/newfor.cpp @@ -16,9 +16,7 @@ // Packet Subtitles are stored here -// uint8_t subtitleCache [SUBTITLEPACKETCOUNT][PACKETSIZE]; /// Storage for 8 packets, 45 bytes per packet. (for packetCache) - -static uint8_t _page; /// Page number (in hex). This is set by Page Init +static uint8_t _page; /// Page number (in hex). This is set by Page Init static uint8_t _rowcount; /// Number of rows in this subtitle // static char packet[PACKETSIZE]; @@ -26,16 +24,16 @@ using namespace vbit; // This is not so pretty. @todo Factor this out of TCPClient static int -vbi_unham8 (unsigned int c) +vbi_unham8 (unsigned int c) { - return _vbi_hamm8_inv[(uint8_t) c]; + return Hamming8DecodeTable[(uint8_t) c]; } Newfor::Newfor(PacketSubtitle* subtitle) : - _subtitle(subtitle) + _subtitle(subtitle) { - ttxpage.SetSubCode(0); + ttxpage.SetSubCode(0); } Newfor::~Newfor() @@ -45,10 +43,12 @@ Newfor::~Newfor() /** initNu4 * @detail Initialise the buffers used by Newfor */ -//void InitNu4() -//{ -// bufferInit(packetCache ,(char*)subtitleCache ,SUBTITLEPACKETCOUNT); -//} +/* +void Newfor::InitNu4() +{ + bufferInit(packetCache, (char*)subtitleCache ,SUBTITLEPACKETCOUNT); +} +*/ /** @@ -61,46 +61,41 @@ Newfor::~Newfor() */ int Newfor::SoftelPageInit(char* cmd) { - int page=0; - int n; - - - // Useless leading 0 - n=vbi_unham8(cmd[1]); - if (n<0) return 0x900; // @todo This is an error. - // Hundreds - n=vbi_unham8(cmd[2]); - if (n<1 || n>8) return 0x901; - page=n*0x100; - // tens (hex allowed!) - n=vbi_unham8(cmd[3]); - if (n<0 || n>0x0f) return 0x902; - page+=n*0x10; - // units - n=vbi_unham8(cmd[4]); - if (n<0 || n>0x0f) return 0x903; - page+=n; - _page=page; - ttxpage.SetPageNumber(page*0x100); - return page; + int page=0; + int n; + + // Useless leading 0 + n=vbi_unham8(cmd[1]); + if (n<0) return 0x900; // @todo This is an error. + n=vbi_unham8(cmd[2]); // Hundreds + if (n<1 || n>8) return 0x901; + page=n*0x100; // tens (hex allowed!) + n=vbi_unham8(cmd[3]); + if (n<0 || n>0x0f) return 0x902; + page+=n*0x10; // units + n=vbi_unham8(cmd[4]); + if (n<0 || n>0x0f) return 0x903; + page+=n; + _page=page; + ttxpage.SetPageNumber(page*0x100); + return page; } void Newfor::SubtitleOnair(char* response) { - strcpy(response,"Response not implemented, sorry\n"); - // Send the page to the subtitle object in the service thread, then clear the lines. - _subtitle->SendSubtitle(&ttxpage); - - for (int i=0;i<24;i++) // Some broadcasters sent the subs out more than once. We don't. - { - ttxpage.SetRow(i," "); - } - + strcpy(response,"Response not implemented, sorry\n"); + // Send the page to the subtitle object in the service thread, then clear the lines. + _subtitle->SendSubtitle(&ttxpage); + + for (int i=0;i<24;i++) // Some broadcasters sent the subs out more than once. We don't. + { + ttxpage.SetRow(i," "); + } } void Newfor::SubtitleOffair() { - _subtitle->SendSubtitle(&ttxpage); // OnAir will already have cleared out these lines so just send the page again + _subtitle->SendSubtitle(&ttxpage); // OnAir will already have cleared out these lines so just send the page again } /** @@ -109,11 +104,11 @@ void Newfor::SubtitleOffair() */ int Newfor::GetRowCount(char* cmd) { - int n=vbi_unham8(cmd[1]); - if (n>7) - n=0; - _rowcount=n; - return n; + int n=vbi_unham8(cmd[1]); + if (n>7) + n=0; + _rowcount=n; + return n; } /** @@ -125,8 +120,8 @@ int Newfor::GetRowCount(char* cmd) */ void Newfor::saveSubtitleRow(uint8_t mag, uint8_t row, char* cmd) { - (void)mag; // temporary silence error about unused parameter - // What @todo about the mag? This needs to be decoded and passed on - if (cmd[0]==0) cmd[0]='?'; // @todo Temporary measure to defeat null strings (this will inevitably multiply problems!) - ttxpage.SetRow(row, cmd); + (void)mag; // temporary silence error about unused parameter + // What @todo about the mag? This needs to be decoded and passed on + if (cmd[0]==0) cmd[0]='?'; // @todo Temporary measure to defeat null strings (this will inevitably multiply problems!) + ttxpage.SetRow(row, cmd); } diff --git a/newfor.h b/newfor.h index 322efc1..7da50a9 100644 --- a/newfor.h +++ b/newfor.h @@ -29,68 +29,65 @@ namespace vbit { -class Newfor -{ - public: - Newfor(PacketSubtitle* subtitle=nullptr); - ~Newfor(); - - /** - * @brief Put the previously loaded subtitle to the previously select page - * @param response String message to send back to the client - */ - void SubtitleOnair(char* response); - int SoftelPageInit(char* cmd); - - /** InitNewfor - * Initialise the subtitle buffer - */ - void InitNewfor(); - - /** - * Clear down subtitles immediately - */ - void SubtitleOffair(); - - /** - * Start of a Subtitle Data command - * @return Row count 1..7, or 0 if invalid - */ - int GetRowCount(char* cmd); - - /** - * Creates a packet of Newfor data. - */ - void saveSubtitleRow(uint8_t mag, uint8_t row, char* cmd); - - - private: - // Constants - static const uint8_t SUBTITLEPACKETCOUNT=8; - /** These are the two responses possible - * Only Page Init and Subtitle Data should respond with these ASCII codes. - */ - static const uint8_t ACK=0x06; - static const uint8_t NACK=0x15; - - // member variables - TTXPage ttxpage; - - // member functions - /** - * @detail Expect four characters - * 1: Ham 0 (always 0x15) - * 2: Page number hundreds hammed. 1..8 - * 3: Page number tens hammed - * Although it says HTU, in keeping with the standard we will work in hex. - */ - char subs[(40+1)*7]; // One byte for row number plus 40 bytes, seven times. - -// instead of this we populate a ttxpage onject -// extern bufferpacket packetCache[1]; // Commands are read into here, and transferred out when OnAir - PacketSubtitle* _subtitle; - -}; - + class Newfor + { + public: + Newfor(PacketSubtitle* subtitle=nullptr); + ~Newfor(); + + /** + * @brief Put the previously loaded subtitle to the previously select page + * @param response String message to send back to the client + */ + void SubtitleOnair(char* response); + int SoftelPageInit(char* cmd); + + /** InitNewfor + * Initialise the subtitle buffer + */ + void InitNewfor(); + + /** + * Clear down subtitles immediately + */ + void SubtitleOffair(); + + /** + * Start of a Subtitle Data command + * @return Row count 1..7, or 0 if invalid + */ + int GetRowCount(char* cmd); + + /** + * Creates a packet of Newfor data. + */ + void saveSubtitleRow(uint8_t mag, uint8_t row, char* cmd); + + private: + // Constants + static const uint8_t SUBTITLEPACKETCOUNT=8; + /** These are the two responses possible + * Only Page Init and Subtitle Data should respond with these ASCII codes. + */ + static const uint8_t ACK=0x06; + static const uint8_t NACK=0x15; + + // member variables + TTXPage ttxpage; + + // member functions + /** + * @detail Expect four characters + * 1: Ham 0 (always 0x15) + * 2: Page number hundreds hammed. 1..8 + * 3: Page number tens hammed + * Although it says HTU, in keeping with the standard we will work in hex. + */ + char subs[(40+1)*7]; // One byte for row number plus 40 bytes, seven times. + + // instead of this we populate a ttxpage onject + // extern bufferpacket packetCache[1]; // Commands are read into here, and transferred out when OnAir + PacketSubtitle* _subtitle; + }; } #endif diff --git a/packet.cpp b/packet.cpp index e7feb95..720c172 100644 --- a/packet.cpp +++ b/packet.cpp @@ -25,29 +25,39 @@ void Packet::SetRow(int mag, int row, std::string val, PageCoding coding) switch(coding) { case CODING_PER_PACKET: + { _coding = TTXPage::ReturnPageCoding(_packet[5] & 0xF); // set packet coding based on first byte of packet /* fallthrough */ + [[gnu::fallthrough]]; + } case CODING_13_TRIPLETS: case CODING_HAMMING_8_4: case CODING_HAMMING_7BIT_GROUPS: - _packet[5] = HamTab[_packet[5] & 0x0F]; // first byte is hamming 8/4 coded + { + _packet[5] = Hamming8EncodeTable[_packet[5] & 0x0F]; // first byte is hamming 8/4 coded break; - + } case CODING_7BIT_TEXT: - _packet[5] = ParTab[_packet[5] & 0x7f]; // set parity on first byte + { + _packet[5] = OddParityTable[_packet[5] & 0x7f]; // set parity on first byte + } default: + { break; + } } switch(_coding) { default: // treat an invalid coding as 7-bit text case CODING_7BIT_TEXT: + { // first byte parity already set by first switch statement Parity(6); break; - + } case CODING_13_TRIPLETS: + { // Special handler to allow stuffing enhancement packets in as OL rows // Each 18 bits of data for a triplet is coded in the input line as // three bytes least significant first where each byte contains 6 data @@ -55,45 +65,50 @@ void Packet::SetRow(int mag, int row, std::string val, PageCoding coding) // designation code is 8/4 hamming coded by first switch statement /* 0x0a and 0x00 in the hammed output is causing a problem so disable this until they are fixed (output will be gibberish) */ int triplet; - for (int i = 1; i<=13; i++){ + for (int i = 1; i<=13; i++) + { triplet = _packet[i*3+3] & 0x3F; triplet |= (_packet[i*3+4] & 0x3F) << 6; triplet |= (_packet[i*3+5] & 0x3F) << 12; - SetTriplet(i, triplet); + Hamming24EncodeTriplet(i, triplet); } break; - + } case CODING_HAMMING_8_4: + { // first byte already hamming 8/4 coded by first switch statement for (int i = 1; i<40; i++) { - _packet[5+i] = HamTab[_packet[5+i] & 0x0F]; + _packet[5+i] = Hamming8EncodeTable[_packet[5+i] & 0x0F]; } break; - + } case CODING_HAMMING_7BIT_GROUPS: + { // first byte already hamming 8/4 coded by first switch statement for (int i = 1; i<8; i++) { - _packet[5+i] = HamTab[_packet[5+i] & 0x0F]; + _packet[5+i] = Hamming8EncodeTable[_packet[5+i] & 0x0F]; } for (int i = 8; i<20; i++) { - _packet[5+i] = ParTab[(uint8_t)(_packet[5+i]&0x7f)]; + _packet[5+i] = OddParityTable[(uint8_t)(_packet[5+i]&0x7f)]; } for (int i = 20; i<28; i++) { - _packet[5+i] = HamTab[_packet[5+i] & 0x0F]; + _packet[5+i] = Hamming8EncodeTable[_packet[5+i] & 0x0F]; } for (int i = 28; i<40; i++) { - _packet[5+i] = ParTab[(uint8_t)(_packet[5+i]&0x7f)]; + _packet[5+i] = OddParityTable[(uint8_t)(_packet[5+i]&0x7f)]; } break; - + } case CODING_8BIT_DATA: + { // do nothing to 8-bit data break; + } } } @@ -118,8 +133,8 @@ void Packet::SetMRAG(uint8_t mag, uint8_t row) _packet[1]=0x55; // clock run in _packet[2]=0x27; // framing code - _packet[3]=HamTab[mag%8+((row%2)<<3)]; // mag + bit 3 is the lowest bit of row - _packet[4]=HamTab[((row>>1)&0x0f)]; + _packet[3]=Hamming8EncodeTable[mag%8+((row%2)<<3)]; // mag + bit 3 is the lowest bit of row + _packet[4]=Hamming8EncodeTable[((row>>1)&0x0f)]; _isHeader=row==0; _row=row; _mag=mag; @@ -189,11 +204,11 @@ std::array* Packet::tx(time_t t) _packet[off]=_mag+'0'; _packet[off+1]=_page/0x10+'0'; if (_packet[off+1]>'9') - _packet[off+1]=_packet[off+1]-'0'-10+'A'; // Particularly poor hex conversion algorithm + _packet[off+1]=_packet[off+1]-'0'-10+'A'; // Particularly poor hex conversion algorithm _packet[off+2]=_page%0x10+'0'; if (_packet[off+2]>'9') - _packet[off+2]=_packet[off+2]-'0'-10+'A'; // Particularly poor hex conversion algorithm + _packet[off+2]=_packet[off+2]-'0'-10+'A'; // Particularly poor hex conversion algorithm } // day name - %%a @@ -295,7 +310,8 @@ std::array* Packet::tx(time_t t) // ======= TEMPERATURE ======== off = Packet::GetOffsetOfSubstition("%%%T"); - if (off > -1) { + if (off > -1) + { #ifdef RASPBIAN get_temp(tmpstr); std::copy_n(tmpstr,4,_packet.begin() + off); @@ -309,10 +325,12 @@ std::array* Packet::tx(time_t t) for (;;) { off = Packet::GetOffsetOfSubstition("%t+"); - if (off == -1) { + if (off == -1) + { off = Packet::GetOffsetOfSubstition("%t-"); } - if (off > -1) { + if (off > -1) + { //std::cout << "[test 1]" << _packet << std::endl; get_offset_time(t, _packet.data() + off); // TODO: something with return value //exit(4); @@ -323,7 +341,8 @@ std::array* Packet::tx(time_t t) // ======= NETWORK ======== // Special case for network address. Put %%%%%%%%%%%%%%n to get network address in form xxx.yyy.zzz.aaa with trailing spaces (15 characters total) off = Packet::GetOffsetOfSubstition("%%%%%%%%%%%%%%n"); - if (off > -1) { + if (off > -1) + { #ifndef WIN32 get_net(tmpstr); std::copy_n(tmpstr,15,_packet.begin() + off); @@ -334,14 +353,16 @@ std::array* Packet::tx(time_t t) // ======= TIME AND DATE ======== // Special case for system time. Put %%%%%%%%%%%%timedate to get time and date off = Packet::GetOffsetOfSubstition("%%%%%%%%%%%%timedate"); - if (off > -1) { + if (off > -1) + { strftime(tmpstr, 21, "\x02%a %d %b\x03%H:%M/%S", timeinfo); std::copy_n(tmpstr,20,_packet.begin() + off); } // ======= VERSION ======== // %%%%%V version number eg. v2.0.0 off = Packet::GetOffsetOfSubstition("%%%%%V"); - if (off > -1) { + if (off > -1) + { std::copy_n(VBIT2_VERSION,6,_packet.begin() + off); } Parity(5); // redo the parity because substitutions will need processing @@ -356,9 +377,9 @@ void Packet::Header(uint8_t mag, uint8_t page, uint16_t subcode, uint16_t contro { uint8_t cbit; SetMRAG(mag,0); - _packet[5]=HamTab[page%0x10]; - _packet[6]=HamTab[page/0x10]; - _packet[7]=HamTab[(subcode&0x0f)]; // S1 four bits + _packet[5]=Hamming8EncodeTable[page%0x10]; + _packet[6]=Hamming8EncodeTable[page/0x10]; + _packet[7]=Hamming8EncodeTable[(subcode&0x0f)]; // S1 four bits subcode>>=4; // Map the page settings control bits from MiniTED to actual teletext packet. // To find the MiniTED settings look at the tti format document. @@ -366,27 +387,28 @@ void Packet::Header(uint8_t mag, uint8_t page, uint16_t subcode, uint16_t contro // So for each bit in ETSI document, just divide the bit number by 2 to find the target location. // Where ETSI says bit 8,6,4,2 this maps to 4,3,2,1 (where the bits are numbered 1 to 8) cbit=0; - if (control & 0x4000) cbit=0x08; // C4 Erase page - _packet[8]=HamTab[(subcode&0x07) | cbit]; // S2 (3 bits) add C4 + if (control & 0x4000) cbit=0x08; // C4 Erase page + _packet[8]=Hamming8EncodeTable[(subcode&0x07) | cbit]; // S2 (3 bits) add C4 subcode>>=4; - _packet[9]=HamTab[(subcode&0x0f)]; // S3 four bits + _packet[9]=Hamming8EncodeTable[(subcode&0x0f)]; // S3 four bits subcode>>=4; + cbit=0; - // Not sure if these bits are reversed. C5 and C6 are indistinguishable - if (control & 0x0002) cbit=0x08; // C6 Subtitle - if (control & 0x0001) cbit|=0x04; // C5 Newsflash - - _packet[10]=HamTab[(subcode&0x03) | cbit]; // S4 C6, C5 + if (control & 0x0001) cbit=0x04; // C5 Newsflash + if (control & 0x0002) cbit|=0x08; // C6 Subtitle + _packet[10]=Hamming8EncodeTable[(subcode&0x03) | cbit]; // S4 C6, C5 + cbit=0; - if (control & 0x0004) cbit=0x01; // C7 Suppress Header - if (control & 0x0008) cbit|=0x02; // C8 Update - if (control & 0x0010) cbit|=0x04; // C9 Interrupted sequence - if (control & 0x0020) cbit|=0x08; // C10 Inhibit display - - _packet[11]=HamTab[cbit]; // C7 to C10 - cbit=(control & 0x0380) >> 6; // Shift the language bits C12,C13,C14. - // if (control & 0x0040) cbit|=0x01; // C11 serial/parallel *** We only work in parallel mode, Serial would mean a different packet ordering. - _packet[12]=HamTab[cbit]; // C11 to C14 (C11=0 is parallel, C12,C13,C14 language) + if (control & 0x0004) cbit=0x01; // C7 Suppress Header + if (control & 0x0008) cbit|=0x02; // C8 Update + if (control & 0x0010) cbit|=0x04; // C9 Interrupted sequence + if (control & 0x0020) cbit|=0x08; // C10 Inhibit display + _packet[11]=Hamming8EncodeTable[cbit]; // C7 to C10 + + cbit=(control & 0x0380) >> 6; // Shift the language bits C12,C13,C14. + + // if (control & 0x0040) cbit|=0x01; // C11 serial/parallel *** We only work in parallel mode, Serial would mean a different packet ordering. + _packet[12]=Hamming8EncodeTable[cbit]; // C11 to C14 (C11=0 is parallel, C12,C13,C14 language) _page=page; } @@ -408,7 +430,7 @@ void Packet::Parity(uint8_t offset) //uint8_t c; for (i=offset;i> 4]; // page tens - _packet[p++]=HamTab[0xF]; // subcode S1 - _packet[p++]=HamTab[((cRelMag & 1) << 3) | 7]; - _packet[p++]=HamTab[0xF]; - _packet[p++]=HamTab[((cRelMag & 6) << 1) | 3]; + _packet[p++]=Hamming8EncodeTable[nLink & 0xF]; // page units + _packet[p++]=Hamming8EncodeTable[(nLink & 0xF0) >> 4]; // page tens + _packet[p++]=Hamming8EncodeTable[0xF]; // subcode S1 + _packet[p++]=Hamming8EncodeTable[((cRelMag & 1) << 3) | 7]; // subcode S2 + M1 + _packet[p++]=Hamming8EncodeTable[0xF]; // subcode S3 + _packet[p++]=Hamming8EncodeTable[((cRelMag & 6) << 1) | 3]; // subcode S4 + M2, M3 } } @@ -449,13 +471,14 @@ int Packet::IDLA(uint8_t datachannel, uint8_t flags, uint8_t ial, uint32_t spa, SetMRAG(datachannel & 0x7,((datachannel & 8) >> 3) + 30); - _packet[5]=HamTab[flags & 0xe]; // Format Type - _packet[6]=HamTab[ial&0xf]; // Interpretation and Address Length + _packet[5]=Hamming8EncodeTable[flags & 0xe]; // Format Type + _packet[6]=Hamming8EncodeTable[ial&0xf]; // Interpretation and Address Length uint8_t p = 7; - for (uint8_t i = 0; i < (ial&0x7) && i < 7; i++){ - _packet[p++] = HamTab[(spa >> (4 * i)) & 0xf]; // variable number of Service Packet Address nibbles + for (uint8_t i = 0; i < (ial&0x7) && i < 7; i++) + { + _packet[p++] = Hamming8EncodeTable[(spa >> (4 * i)) & 0xf]; // variable number of Service Packet Address nibbles } if (flags & IDLA_RI) @@ -493,7 +516,8 @@ int Packet::IDLA(uint8_t datachannel, uint8_t flags, uint8_t ial, uint32_t spa, { sameCount++; - if ((uint8_t)(_packet[p]) == (uint8_t)(_packet[p-1])){ + if ((uint8_t)(_packet[p]) == (uint8_t)(_packet[p-1])) + { if (sameCount > 7 && p < 42) { sameCount = 0; @@ -517,7 +541,8 @@ int Packet::IDLA(uint8_t datachannel, uint8_t flags, uint8_t ial, uint32_t spa, uint16_t crc = 0; - for (uint8_t i = startOfCRC; i < 43; i++){ + for (uint8_t i = startOfCRC; i < 43; i++) + { IDLcrc(&crc, _packet[i]); // calculate CRC for user data } @@ -543,7 +568,8 @@ void Packet::IDLcrc(uint16_t *crc, uint8_t data) { *crc ^= data; - for (uint8_t i = 0; i < 8; i++){ + for (uint8_t i = 0; i < 8; i++) + { *crc = (*crc & 1) ? (*crc >> 1) ^ 0x8940 : (*crc >> 1); } } @@ -552,7 +578,8 @@ void Packet::ReverseCRC(uint16_t *crc, uint8_t byte) { /* reverse the IDL A crc */ uint8_t bit; - for (uint8_t i = 0; i < 8; i++){ + for (uint8_t i = 0; i < 8; i++) + { bit = (byte >> (7-i)) & 1; *crc = (*crc & 0x8000) ? (((*crc << 1) | bit) ^ 0x1281) : ((*crc << 1) | bit); } @@ -612,36 +639,24 @@ bool Packet::get_net(char* str) } #endif -void Packet::SetTriplet(int ix, int triplet) -{ - uint8_t t[4]; - if (ix<1) return; - vbi_ham24p(t,triplet); - // Now stuff the result in the packet - _packet[ix*3+3]=t[0]; - _packet[ix*3+4]=t[1]; - _packet[ix*3+5]=t[2]; -} - -void Packet::vbi_ham24p(uint8_t * p, unsigned int c) +void Packet::Hamming24EncodeTriplet(uint8_t index, uint32_t triplet) { - unsigned int D5_D11; - unsigned int D12_D18; - unsigned int P5, P6; - unsigned int Byte_0; + if (index<1) return; + + uint8_t D5_D11; + uint8_t D12_D18; + uint8_t P5, P6; + uint8_t Byte_0; - Byte_0 = (_vbi_hamm24_fwd_0 [(c >> 0) & 0xFF] - ^ _vbi_hamm24_fwd_1 [(c >> 8) & 0xFF] - ^ _vbi_hamm24_fwd_2 [(c >> 16) & 0x03]); - p[0] = Byte_0; + Byte_0 = (Hamming24EncodeTable0[(triplet >> 0) & 0xFF] ^ Hamming24EncodeTable1[(triplet >> 8) & 0xFF] ^ Hamming24EncodeTable2[(triplet >> 16) & 0x03]); + _packet[index*3+3] = Byte_0; - D5_D11 = (c >> 4) & 0x7F; - D12_D18 = (c >> 11) & 0x7F; + D5_D11 = (triplet >> 4) & 0x7F; + D12_D18 = (triplet >> 11) & 0x7F; - P5 = 0x80 & ~(_vbi_hamm24_inv_par[0][D12_D18] << 2); - p[1] = D5_D11 | P5; + P5 = 0x80 & ~(Hamming24ParityTable[0][D12_D18] << 2); + _packet[index*3+4] = D5_D11 | P5; - P6 = 0x80 & ((_vbi_hamm24_inv_par[0][Byte_0] - ^ _vbi_hamm24_inv_par[0][D5_D11]) << 2); - p[2] = D12_D18 | P6; + P6 = 0x80 & ((Hamming24ParityTable[0][Byte_0] ^ Hamming24ParityTable[0][D5_D11]) << 2); + _packet[index*3+5] = D12_D18 | P6; } diff --git a/packet.h b/packet.h index 21b30bd..7bdb204 100644 --- a/packet.h +++ b/packet.h @@ -9,7 +9,6 @@ #include #include #include "tables.h" -#include "hamm-tables.h" #include #include "ttxpage.h" @@ -139,21 +138,13 @@ namespace vbit bool get_offset_time(time_t t, uint8_t* str); bool get_net(char* str); + /** Hamming 24/18 - * The incoming triplet should be packed 18 bits of an int 32 representing D1..D18 - * The int is repacked with parity bits - */ - void SetTriplet(int ix, int triplet); - - /** - * @param p A Hamming 24/18 protected 24 bit word will be stored here, - * last significant byte first, lsb first transmitted. - * @param c Integer between 0 ... 1 << 18 - 1. - * - * Encodes an 18 bit word with Hamming 24/18 protection - * as specified in ETS 300 706, Section 8.3. + * Hamming 24/18 encode a triplet and place at appropriate index in packet + * The incoming triplet should be packed 18 bits of an uint32_t representing D1..D18 + * The triplet is repacked with parity bits */ - void vbi_ham24p(uint8_t *p, unsigned int c); + void Hamming24EncodeTriplet(uint8_t index, uint32_t triplet); #ifdef RASPBIAN bool get_temp(char* str); diff --git a/packet830.cpp b/packet830.cpp index 0f7bd9f..fa52579 100644 --- a/packet830.cpp +++ b/packet830.cpp @@ -3,19 +3,19 @@ using namespace vbit; Packet830::Packet830(ttx::Configure *configure) : - _configure(configure) + _configure(configure) { - //ctor - ClearEvent(EVENT_P830_FORMAT_1); - ClearEvent(EVENT_P830_FORMAT_2_LABEL_0 ); - ClearEvent(EVENT_P830_FORMAT_2_LABEL_1 ); - ClearEvent(EVENT_P830_FORMAT_2_LABEL_2 ); - ClearEvent(EVENT_P830_FORMAT_2_LABEL_3 ); + //ctor + ClearEvent(EVENT_P830_FORMAT_1); + ClearEvent(EVENT_P830_FORMAT_2_LABEL_0 ); + ClearEvent(EVENT_P830_FORMAT_2_LABEL_1 ); + ClearEvent(EVENT_P830_FORMAT_2_LABEL_2 ); + ClearEvent(EVENT_P830_FORMAT_2_LABEL_3 ); } Packet830::~Packet830() { - //dtor + //dtor } Packet* Packet830::GetPacket(Packet* p) @@ -36,23 +36,23 @@ Packet* Packet830::GetPacket(Packet* p) uint8_t m = _configure->GetInitialMag(); uint8_t pn = _configure->GetInitialPage(); uint16_t sc = _configure->GetInitialSubcode(); - data.at(1) = HamTab[pn & 0xF]; - data.at(2) = HamTab[(pn & 0xF0) >> 4]; - data.at(3) = HamTab[sc & 0xF]; - data.at(4) = HamTab[((sc & 0xF0) >> 4) | ((m & 1) << 3)]; - data.at(5) = HamTab[(sc & 0xF00) >> 8]; - data.at(6) = HamTab[((sc & 0xF000) >> 12) | ((m & 6) << 1)]; + data.at(1) = Hamming8EncodeTable[pn & 0xF]; + data.at(2) = Hamming8EncodeTable[(pn & 0xF0) >> 4]; + data.at(3) = Hamming8EncodeTable[sc & 0xF]; + data.at(4) = Hamming8EncodeTable[((sc & 0xF0) >> 4) | ((m & 1) << 3)]; + data.at(5) = Hamming8EncodeTable[(sc & 0xF00) >> 8]; + data.at(6) = Hamming8EncodeTable[((sc & 0xF000) >> 12) | ((m & 6) << 1)]; std::copy_n(_configure->GetServiceStatusString().begin(), 20, data.begin() + 20); // copy status display from std::string into packet data if (GetEvent(EVENT_P830_FORMAT_1)) { ClearEvent(EVENT_P830_FORMAT_1); - data.at(0) = HamTab[muxed]; // Format 1 designation code + data.at(0) = Hamming8EncodeTable[muxed]; // Format 1 designation code uint16_t nic = _configure->GetNetworkIdentificationCode(); - data.at(7) = _vbi_bit_reverse[(nic & 0xFF00) >> 8]; - data.at(8) = _vbi_bit_reverse[nic & 0xFF]; + data.at(7) = ReverseByteTab[(nic & 0xFF00) >> 8]; + data.at(8) = ReverseByteTab[nic & 0xFF]; /* calculate number of seconds local time is offset from UTC */ tmLocal = localtime(&timeRaw); @@ -100,28 +100,28 @@ Packet* Packet830::GetPacket(Packet* p) if (GetEvent(EVENT_P830_FORMAT_2_LABEL_0)) { ClearEvent(EVENT_P830_FORMAT_2_LABEL_0); - data.at(0) = HamTab[muxed | 2]; // Format 2 designation code + data.at(0) = Hamming8EncodeTable[muxed | 2]; // Format 2 designation code //@todo } if (GetEvent(EVENT_P830_FORMAT_2_LABEL_1)) { ClearEvent(EVENT_P830_FORMAT_2_LABEL_1); - data.at(0) = HamTab[muxed | 2]; // Format 2 designation code + data.at(0) = Hamming8EncodeTable[muxed | 2]; // Format 2 designation code //@todo } if (GetEvent(EVENT_P830_FORMAT_2_LABEL_2)) { ClearEvent(EVENT_P830_FORMAT_2_LABEL_2); - data.at(0) = HamTab[muxed | 2]; // Format 2 designation code + data.at(0) = Hamming8EncodeTable[muxed | 2]; // Format 2 designation code //@todo } if (GetEvent(EVENT_P830_FORMAT_2_LABEL_3)) { ClearEvent(EVENT_P830_FORMAT_2_LABEL_3 ); - data.at(0) = HamTab[muxed | 2]; // Format 2 designation code + data.at(0) = Hamming8EncodeTable[muxed | 2]; // Format 2 designation code //@todo } @@ -138,16 +138,16 @@ bool Packet830::IsReady(bool force) GetEvent(EVENT_P830_FORMAT_2_LABEL_1) || GetEvent(EVENT_P830_FORMAT_2_LABEL_2) || GetEvent(EVENT_P830_FORMAT_2_LABEL_3); - return result; + return result; } long Packet830::calculateMJD(int year, int month, int day) { - // calculate modified julian day number - int a, b, c, d; - a = (month - 14) / 12; - b = day - 32075 + (1461 * (year + 4800 + a) / 4); - c = (367 * (month - 2 - 12 * a) / 12); - d = 3 * (((year + 4900 + a) / 100) / 4); - return b + c - d - 2400001; + // calculate modified julian day number + int a, b, c, d; + a = (month - 14) / 12; + b = day - 32075 + (1461 * (year + 4800 + a) / 4); + c = (367 * (month - 2 - 12 * a) / 12); + d = 3 * (((year + 4900 + a) / 100) / 4); + return b + c - d - 2400001; } diff --git a/packetmag.cpp b/packetmag.cpp index 1bce2db..3e00280 100644 --- a/packetmag.cpp +++ b/packetmag.cpp @@ -35,11 +35,11 @@ PacketMag::PacketMag(uint8_t mag, std::list* pageSet, ttx::Config PacketMag::~PacketMag() { - //dtor - delete _carousel; - delete _specialPages; - delete _normalPages; - delete _updatedPages; + //dtor + delete _carousel; + delete _specialPages; + delete _normalPages; + delete _updatedPages; } Packet* PacketMag::GetPacket(Packet* p) @@ -60,6 +60,7 @@ Packet* PacketMag::GetPacket(Packet* p) switch (_state) { case PACKETSTATE_HEADER: // Start to send out a new page, which may be a simple page or one of a carousel + { if (GetEvent(EVENT_PACKET_29) && _hasPacket29) { if (_mtx.try_lock()) // skip if unable to get lock @@ -117,7 +118,9 @@ Packet* PacketMag::GetPacket(Packet* p) /* rules for the control bits are complicated. There are rules to allow the page to be sent as fragments. Since we aren't doing that, all the flags are left clear except for C9 (interrupted sequence) to keep special pages out of rolling headers */ _status |= 0x0010; /* rules for the subcode are really complicated. The S1 nibble should be the sub page number, S2 is a counter that increments when the page is updated, S3 and S4 hold the last row number */ - } else { + } + else + { // got to the end of the special pages ClearEvent(EVENT_SPECIAL_PAGES); return nullptr; @@ -146,7 +149,8 @@ Packet* PacketMag::GetPacket(Packet* p) } } - if (_page == nullptr){ + if (_page == nullptr) + { // couldn't get a page to send so sent a time filling header p->Header(_magNumber,0xFF,0x0000,0x8010); p->HeaderText(_configure->GetHeaderTemplate()); // Placeholder 32 characters. This gets replaced later @@ -156,7 +160,8 @@ Packet* PacketMag::GetPacket(Packet* p) _thisRow=0; - if (_page->IsCarousel()){ + if (_page->IsCarousel()) + { if (_page->Expired()) { // cycle if timer has expired @@ -181,7 +186,8 @@ Packet* PacketMag::GetPacket(Packet* p) // Handle pages with update bit set in a useful way. // This isn't defined by the specification. - if (_status & PAGESTATUS_C8_UPDATE){ + if (_status & PAGESTATUS_C8_UPDATE) + { // Clear update bit in stored page so that update flag is only transmitted once _page->SetPageStatus(_status & ~PAGESTATUS_C8_UPDATE); @@ -189,7 +195,8 @@ Packet* PacketMag::GetPacket(Packet* p) _status|=PAGESTATUS_C4_ERASEPAGE; } - if (updatedFlag){ + if (updatedFlag) + { // page is updated set interrupted sequence flag and clear UpdatedFlag _status|=PAGESTATUS_C9_INTERRUPTED; } @@ -216,84 +223,108 @@ Packet* PacketMag::GetPacket(Packet* p) // don't apply parity here it will screw up the template. parity for the header is done by tx() later assert(p!=NULL); - if (_page->IsCarousel()){ + if (_page->IsCarousel()) + { links=_page->GetCarouselPage()->GetLinkSet(); - } else { + } + else + { links=_page->GetLinkSet(); } - if ((links[0] & links[1] & links[2] & links[3] & links[4] & links[5]) != 0x8FF){ // only create if links were initialised + if ((links[0] & links[1] & links[2] & links[3] & links[4] & links[5]) != 0x8FF) // only create if links were initialised + { _state=PACKETSTATE_FASTEXT; break; - } else { + } + else + { _lastTxt=_page->GetTxRow(27); // Get _lastTxt ready for packet 27 processing _state=PACKETSTATE_PACKET27; break; } - case PACKETSTATE_PACKET27: - if (_lastTxt) - { - if ((_lastTxt->GetLine()[0] & 0xF) > 3) // designation codes > 3 - p->SetRow(_magNumber, 27, _lastTxt->GetLine(), CODING_13_TRIPLETS); // enhancement linking - else - p->SetRow(_magNumber, 27, _lastTxt->GetLine(), CODING_HAMMING_8_4); // navigation packets (TODO: CRC in DC=0 is wrong) - _lastTxt=_lastTxt->GetNextLine(); - break; - } - _lastTxt=_page->GetTxRow(28); // Get _lastTxt ready for packet 28 processing - _state=PACKETSTATE_PACKET28; // // Intentional fall through to PACKETSTATE_PACKET28 - /* fallthrough */ - case PACKETSTATE_PACKET28: - if (_lastTxt) - { - p->SetRow(_magNumber, 28, _lastTxt->GetLine(), CODING_13_TRIPLETS); - if ((_lastTxt->GetCharAt(0) & 0xF) == 0 || (_lastTxt->GetCharAt(0) & 0xF) == 4) - _hasX28Region = true; // don't generate an X/28/0 for a RE line - _lastTxt=_lastTxt->GetNextLine(); - break; - } - else if (!(_hasX28Region) && (_region != _magRegion)) - { - // create X/28/0 packet for pages which have a region set with RE in file - // this could almost certainly be done more efficiently but it's quite confusing and this is more readable for when it all goes wrong. - std::string val = "@@@tGpCuW@twwCpRA`UBWwDsWwuwwwUwWwuWwE@@"; // default X/28/0 packet - int NOS = (_status & 0x380) >> 7; - int language = NOS | (_region << 3); - int triplet = 0x3C000 | (language << 7); // construct triplet 1 - val.replace(1,1,1,(triplet & 0x3F) | 0x40); - val.replace(2,1,1,((triplet & 0xFC0) >> 6) | 0x40); - val.replace(3,1,1,((triplet & 0x3F000) >> 12) | 0x40); - p->SetRow(_magNumber, 28, val, CODING_13_TRIPLETS); - _lastTxt=_page->GetTxRow(26); // Get _lastTxt ready for packet 26 processing - _state=PACKETSTATE_PACKET26; - break; - } else if (_page->GetPageCoding() == CODING_7BIT_TEXT){ - // X/26 packets next in normal pages - _lastTxt=_page->GetTxRow(26); // Get _lastTxt ready for packet 26 processing - _state=PACKETSTATE_PACKET26; // Intentional fall through to PACKETSTATE_PACKET26 - } else { - // do X/1 to X/25 first and go back to X/26 after - _state=PACKETSTATE_TEXTROW; - return nullptr; - } - /* fallthrough */ - case PACKETSTATE_PACKET26: - if (_lastTxt) - { - p->SetRow(_magNumber, 26, _lastTxt->GetLine(), CODING_13_TRIPLETS); - // Do we have another line? - _lastTxt=_lastTxt->GetNextLine(); - break; - } - if (_page->GetPageCoding() == CODING_7BIT_TEXT){ - _state=PACKETSTATE_TEXTROW; // Intentional fall through to PACKETSTATE_TEXTROW - } else { - // otherwise we end the page here - _state=PACKETSTATE_HEADER; - _thisRow=0; - return nullptr; - } - /* fallthrough */ + } + case PACKETSTATE_PACKET27: + { + if (_lastTxt) + { + if ((_lastTxt->GetLine()[0] & 0xF) > 3) // designation codes > 3 + p->SetRow(_magNumber, 27, _lastTxt->GetLine(), CODING_13_TRIPLETS); // enhancement linking + else + p->SetRow(_magNumber, 27, _lastTxt->GetLine(), CODING_HAMMING_8_4); // navigation packets (TODO: CRC in DC=0 is wrong) + _lastTxt=_lastTxt->GetNextLine(); + break; + } + _lastTxt=_page->GetTxRow(28); // Get _lastTxt ready for packet 28 processing + _state=PACKETSTATE_PACKET28; // // Intentional fall through to PACKETSTATE_PACKET28 + /* fallthrough */ + [[gnu::fallthrough]]; + } + case PACKETSTATE_PACKET28: + { + if (_lastTxt) + { + p->SetRow(_magNumber, 28, _lastTxt->GetLine(), CODING_13_TRIPLETS); + if ((_lastTxt->GetCharAt(0) & 0xF) == 0 || (_lastTxt->GetCharAt(0) & 0xF) == 4) + _hasX28Region = true; // don't generate an X/28/0 for a RE line + _lastTxt=_lastTxt->GetNextLine(); + break; + } + else if (!(_hasX28Region) && (_region != _magRegion)) + { + // create X/28/0 packet for pages which have a region set with RE in file + // this could almost certainly be done more efficiently but it's quite confusing and this is more readable for when it all goes wrong. + std::string val = "@@@tGpCuW@twwCpRA`UBWwDsWwuwwwUwWwuWwE@@"; // default X/28/0 packet + int NOS = (_status & 0x380) >> 7; + int language = NOS | (_region << 3); + int triplet = 0x3C000 | (language << 7); // construct triplet 1 + val.replace(1,1,1,(triplet & 0x3F) | 0x40); + val.replace(2,1,1,((triplet & 0xFC0) >> 6) | 0x40); + val.replace(3,1,1,((triplet & 0x3F000) >> 12) | 0x40); + p->SetRow(_magNumber, 28, val, CODING_13_TRIPLETS); + _lastTxt=_page->GetTxRow(26); // Get _lastTxt ready for packet 26 processing + _state=PACKETSTATE_PACKET26; + break; + } + else if (_page->GetPageCoding() == CODING_7BIT_TEXT) + { + // X/26 packets next in normal pages + _lastTxt=_page->GetTxRow(26); // Get _lastTxt ready for packet 26 processing + _state=PACKETSTATE_PACKET26; // Intentional fall through to PACKETSTATE_PACKET26 + } + else + { + // do X/1 to X/25 first and go back to X/26 after + _state=PACKETSTATE_TEXTROW; + return nullptr; + } + /* fallthrough */ + [[gnu::fallthrough]]; + } + case PACKETSTATE_PACKET26: + { + if (_lastTxt) + { + p->SetRow(_magNumber, 26, _lastTxt->GetLine(), CODING_13_TRIPLETS); + // Do we have another line? + _lastTxt=_lastTxt->GetNextLine(); + break; + } + if (_page->GetPageCoding() == CODING_7BIT_TEXT) + { + _state=PACKETSTATE_TEXTROW; // Intentional fall through to PACKETSTATE_TEXTROW + } + else + { + // otherwise we end the page here + _state=PACKETSTATE_HEADER; + _thisRow=0; + return nullptr; + } + /* fallthrough */ + [[gnu::fallthrough]]; + } case PACKETSTATE_TEXTROW: + { // Find the next row that isn't NULL for (_thisRow++;_thisRow<26;_thisRow++) { @@ -305,11 +336,14 @@ Packet* PacketMag::GetPacket(Packet* p) // Didn't find? End of this page. if (_thisRow>25 || _lastTxt==NULL) { - if(_page->GetPageCoding() == CODING_7BIT_TEXT){ + if(_page->GetPageCoding() == CODING_7BIT_TEXT) + { // if this is a normal page we've finished _state=PACKETSTATE_HEADER; _thisRow=0; - } else { + } + else + { // otherwise go on to X/26 _lastTxt=_page->GetTxRow(26); _state=PACKETSTATE_PACKET26; @@ -321,30 +355,38 @@ Packet* PacketMag::GetPacket(Packet* p) //_outp("J"); if (_lastTxt->IsBlank() && (_configure->GetRowAdaptive() || _page->GetPageFunction() != LOP)) // If a row is empty then skip it if row adaptive mode on, or not a level 1 page { - return nullptr; + return nullptr; } else { - // Assemble the packet - p->SetRow(_magNumber, _thisRow, _lastTxt->GetLine(), _page->GetPageCoding()); - assert(p->IsHeader()!=true); + // Assemble the packet + p->SetRow(_magNumber, _thisRow, _lastTxt->GetLine(), _page->GetPageCoding()); + assert(p->IsHeader()!=true); } } break; + } case PACKETSTATE_FASTEXT: + { p->SetMRAG(_magNumber,27); - if (_page->IsCarousel()){ + if (_page->IsCarousel()) + { links=_page->GetCarouselPage()->GetLinkSet(); - } else { + } + else + { links=_page->GetLinkSet(); } p->Fastext(links,_magNumber); _lastTxt=_page->GetTxRow(27); // Get _lastTxt ready for packet 27 processing _state=PACKETSTATE_PACKET27; // makes no attempt to prevent an FL row and an X/27/0 both being sent break; + } default: + { _state=PACKETSTATE_HEADER;// For now, do the next page return nullptr; + } } return p; // @@ -375,12 +417,13 @@ bool PacketMag::IsReady(bool force) _priorityCount--; if (_priorityCount==0 || force || (_updatedPages->waiting())) // force if there are updated pages waiting { - _priorityCount=_priority; - result=true; + _priorityCount=_priority; + result=true; } } - if (_pageSet->size()>0){ + if (_pageSet->size()>0) + { return result; } else @@ -389,7 +432,8 @@ bool PacketMag::IsReady(bool force) } }; -void PacketMag::SetPacket29(int i, TTXLine *line){ +void PacketMag::SetPacket29(int i, TTXLine *line) +{ _packet29[i] = line; _hasPacket29 = true; @@ -403,11 +447,13 @@ void PacketMag::SetPacket29(int i, TTXLine *line){ } } -void PacketMag::DeletePacket29(){ +void PacketMag::DeletePacket29() +{ _mtx.lock(); for (int i=0;iGetSubtitleRepeats()), _C8Flag(true) { - //ctor + //ctor } PacketSubtitle::~PacketSubtitle() { - //dtor + //dtor } Packet* PacketSubtitle::GetPacket(Packet* p) @@ -28,9 +28,12 @@ Packet* PacketSubtitle::GetPacket(Packet* p) switch (_state) { case SUBTITLE_STATE_IDLE : // This can not happen. We can't put out a packet if we are in idle. + { std::cerr << "[PacketSubtitle::GetPacket] can not happen" << std::endl; break; + } case SUBTITLE_STATE_HEADER: + { std::cerr << "[PacketSubtitle::GetPacket] Header. repeat count=" << (int)_repeatCount << std::endl; // Construct the header packet and then wait for a field { @@ -43,12 +46,14 @@ Packet* PacketSubtitle::GetPacket(Packet* p) } p->Header(mag, page, 0, status); // Create the header } - p->HeaderText("XENOXXX INDUSTRIES CLOCK"); // Only Jason will see this if he decodes a tape. + p->HeaderText("XENOXXX INDUSTRIES CLOCK"); // Only Jason will see this if he decodes a tape. ClearEvent(EVENT_FIELD); _state=SUBTITLE_STATE_TEXT_ROW; - _rowCount=1; // Set up iterator for page rows + _rowCount=1; // Set up iterator for page rows break; + } case SUBTITLE_STATE_TEXT_ROW: + { // 1) Copy the next non-null row to p if (_rowCount<24) { @@ -64,9 +69,12 @@ Packet* PacketSubtitle::GetPacket(Packet* p) // @todo Check that IsReady prevents this branch from ever being taken } break; + } case SUBTITLE_STATE_NUMBER_ITEMS: + { std::cerr << "[PacketSubtitle::IsReady] This is impossible" << std::endl; break; + } } _mtx.unlock(); // unlock the critical section return p; @@ -83,23 +91,28 @@ bool PacketSubtitle::IsReady(bool force) _mtx.lock(); // lock the critical section switch (_state) { - case SUBTITLE_STATE_IDLE : // Process starts with EVENT_SUBTITLE - if (GetEvent(EVENT_SUBTITLE)) + case SUBTITLE_STATE_IDLE : // Process starts with EVENT_SUBTITLE { - ClearEvent(EVENT_SUBTITLE); - _state=SUBTITLE_STATE_HEADER; - result=true; + if (GetEvent(EVENT_SUBTITLE)) + { + ClearEvent(EVENT_SUBTITLE); + _state=SUBTITLE_STATE_HEADER; + result=true; + } + break; } - break; - case SUBTITLE_STATE_HEADER: - if (GetEvent(EVENT_FIELD)) + case SUBTITLE_STATE_HEADER: { - result=true; + if (GetEvent(EVENT_FIELD)) + { + result=true; + } + break; } - break; - case SUBTITLE_STATE_TEXT_ROW: - // Iterate through to the next non blank row. - for (;_rowCount<24;_rowCount++) + case SUBTITLE_STATE_TEXT_ROW: + { + // Iterate through to the next non blank row. + for (;_rowCount<24;_rowCount++) { if (!_page[_swap].GetRow(_rowCount)->IsBlank()) { @@ -144,9 +157,12 @@ bool PacketSubtitle::IsReady(bool force) } } break; - case SUBTITLE_STATE_NUMBER_ITEMS: - std::cerr << "[PacketSubtitle::IsReady] This is impossible" << std::endl; - break; + } + case SUBTITLE_STATE_NUMBER_ITEMS: + { + std::cerr << "[PacketSubtitle::IsReady] This is impossible" << std::endl; + break; + } } _mtx.unlock(); // unlock the critical section return result; diff --git a/pagelist.cpp b/pagelist.cpp index 1525217..55401af 100644 --- a/pagelist.cpp +++ b/pagelist.cpp @@ -82,7 +82,7 @@ int PageList::ReadDirectory(std::string filepath) } //p=new TTXPageStream(filepath+"/"+dirp->d_name); - if (std::string(dirp->d_name).find(".tti") != std::string::npos) // Is the file type .tti or ttix? + if (std::string(dirp->d_name).find(".tti") != std::string::npos) // Is the file type .tti or ttix? { q=new TTXPageStream(filepath+"/"+dirp->d_name); // If the page loaded, then push it into the appropriate magazine @@ -128,17 +128,23 @@ void PageList::CheckForPacket29(TTXPageStream* page) switch (tempLine->GetCharAt(0)) { case '@': + { Packet29Flag = true; _mag[mag]->SetPacket29(0, new TTXLine(tempLine->GetLine(), true)); break; + } case 'A': + { Packet29Flag = true; _mag[mag]->SetPacket29(1, new TTXLine(tempLine->GetLine(), true)); break; + } case 'D': + { Packet29Flag = true; _mag[mag]->SetPacket29(2, new TTXLine(tempLine->GetLine(), true)); break; + } } tempLine = tempLine->GetNextLine(); diff --git a/service.cpp b/service.cpp index 4047ab7..90bd7de 100644 --- a/service.cpp +++ b/service.cpp @@ -73,17 +73,23 @@ int Service::run() if (_debug->IsReady()) // Special case for debug. Ensures it can have the first line of field { - if (_debug->GetPacket(pkt) != nullptr){ + if (_debug->GetPacket(pkt) != nullptr) + { _packetOutput(pkt); - } else { + } + else + { _packetOutput(filler); } } else if (_subtitle->IsReady()) // Special case for subtitles. Subtitles always go if there is one waiting { - if (_subtitle->GetPacket(pkt) != nullptr){ + if (_subtitle->GetPacket(pkt) != nullptr) + { _packetOutput(pkt); - } else { + } + else + { _packetOutput(filler); } } @@ -125,9 +131,12 @@ int Service::run() if (p) { // GetPacket returns nullptr if the pkt isn't valid - if it's null go round again. - if (p->GetPacket(pkt) != nullptr){ + if (p->GetPacket(pkt) != nullptr) + { _packetOutput(pkt); - } else { + } + else + { _packetOutput(filler); } } @@ -166,7 +175,9 @@ void Service::_updateEvents() { masterClock++; // step the master clock - if (masterClock < now || masterClock > now + FORWARDSBUFFER + 1){ // if internal master clock is behind real time, or too far ahead, resynchronise it. + // if internal master clock is behind real time, or too far ahead, resynchronise it. + if (masterClock < now || masterClock > now + FORWARDSBUFFER + 1) + { masterClock = now; std::cerr << "[Service::_updateEvents] Resynchronising master clock" << std::endl; // emit warning on stderr @@ -174,7 +185,8 @@ void Service::_updateEvents() _configure->SetMasterClock(masterClock); // update - if (masterClock%15==0){ // how often do we want to trigger sending special packets? + if (masterClock%15==0) // TODO: how often do we want to trigger sending special packets? + { for (std::list::const_iterator iterator = _Sources.begin(), end = _Sources.end(); iterator != end; ++iterator) { (*iterator)->SetEvent(EVENT_SPECIAL_PAGES); @@ -194,21 +206,31 @@ void Service::_updateEvents() switch (_fieldCounter/10) { case 0: + { ev=EVENT_P830_FORMAT_1; break; + } case 1: + { ev=EVENT_P830_FORMAT_2_LABEL_0; break; + } case 2: + { ev=EVENT_P830_FORMAT_2_LABEL_1; break; + } case 3: + { ev=EVENT_P830_FORMAT_2_LABEL_2; break; + } case 4: + { ev=EVENT_P830_FORMAT_2_LABEL_3; break; } + } for (std::list::const_iterator iterator = _Sources.begin(), end = _Sources.end(); iterator != end; ++iterator) { (*iterator)->SetEvent(ev); @@ -232,7 +254,7 @@ void Service::_packetOutput(vbit::Packet* pkt) static std::array tmp; for (unsigned int i=0;i<(p->size());i++) { - tmp[i]=_vbi_bit_reverse[p->at(i)]; + tmp[i]=ReverseByteTab[p->at(i)]; } p = &tmp; } diff --git a/specialpages.cpp b/specialpages.cpp index d9b94b0..367d50b 100644 --- a/specialpages.cpp +++ b/specialpages.cpp @@ -51,10 +51,10 @@ TTXPageStream* SpecialPages::NextPage() { _page = nullptr; } - else if (_page->IsCarousel() && _page->GetCarouselPage() == NULL) - { - _page->StepNextSubpageNoLoop(); // ensure we don't point at a null subpage - } + else if (_page->IsCarousel() && _page->GetCarouselPage() == NULL) + { + _page->StepNextSubpageNoLoop(); // ensure we don't point at a null subpage + } if (_page) { diff --git a/tables.cpp b/tables.cpp index 4418e6b..a3788ec 100644 --- a/tables.cpp +++ b/tables.cpp @@ -22,260 +22,288 @@ * arising out of or in connection with the use or performance of * this software. *************************************************************************** **/ - + #include "tables.h" - -/*-------------------------------------- -*TABLES ---------------------------------------*/ -/* Parity table. -* Use 1st half to add odd parity, -* Use 2nd half to add even parity -* Both halves to remove odd parity - signals error if -ve. -*/ -const unsigned char ParTab[] = { - 0x80,0x01,0x02,0x83,0x04,0x85,0x86,0x07, - 0x08,0x89,0x8A,0x0B,0x8C,0x0D,0x0E,0x8F, - 0x10,0x91,0x92,0x13,0x94,0x15,0x16,0x97, - 0x98,0x19,0x1A,0x9B,0x1C,0x9D,0x9E,0x1F, - 0x20,0xA1,0xA2,0x23,0xA4,0x25,0x26,0xA7, - 0xA8,0x29,0x2A,0xAB,0x2C,0xAD,0xAE,0x2F, - 0xB0,0x31,0x32,0xB3,0x34,0xB5,0xB6,0x37, - 0x38,0xB9,0xBA,0x3B,0xBC,0x3D,0x3E,0xBF, - 0x40,0xC1,0xC2,0x43,0xC4,0x45,0x46,0xC7, - 0xC8,0x49,0x4A,0xCB,0x4C,0xCD,0xCE,0x4F, - 0xD0,0x51,0x52,0xD3,0x54,0xD5,0xD6,0x57, - 0x58,0xD9,0xDA,0x5B,0xDC,0x5D,0x5E,0xDF, - 0xE0,0x61,0x62,0xE3,0x64,0xE5,0xE6,0x67, - 0x68,0xE9,0xEA,0x6B,0xEC,0x6D,0x6E,0xEF, - 0x70,0xF1,0xF2,0x73,0xF4,0x75,0x76,0xF7, - 0xF8,0x79,0x7A,0xFB,0x7C,0xFD,0xFE,0x7F, - 0x00,0x81,0x82,0x03,0x84,0x05,0x06,0x87, - 0x88,0x09,0x0A,0x8B,0x0C,0x8D,0x8E,0x0F, - 0x90,0x11,0x12,0x93,0x14,0x95,0x96,0x17, - 0x18,0x99,0x9A,0x1B,0x9C,0x1D,0x1E,0x9F, - 0xA0,0x21,0x22,0xA3,0x24,0xA5,0xA6,0x27, - 0x28,0xA9,0xAA,0x2B,0xAC,0x2D,0x2E,0xAF, - 0x30,0xB1,0xB2,0x33,0xB4,0x35,0x36,0xB7, - 0xB8,0x39,0x3A,0xBB,0x3C,0xBD,0xBE,0x3F, - 0xC0,0x41,0x42,0xC3,0x44,0xC5,0xC6,0x47, - 0x48,0xC9,0xCA,0x4B,0xCC,0x4D,0x4E,0xCF, - 0x50,0xD1,0xD2,0x53,0xD4,0x55,0x56,0xD7, - 0xD8,0x59,0x5A,0xDB,0x5C,0xDD,0xDE,0x5F, - 0x60,0xE1,0xE2,0x63,0xE4,0x65,0x66,0xE7, - 0xE8,0x69,0x6A,0xEB,0x6C,0xED,0xEE,0x6F, - 0xF0,0x71,0x72,0xF3,0x74,0xF5,0xF6,0x77, - 0x78,0xF9,0xFA,0x7B,0xFC,0x7D,0x7E,0xFF}; /*------------------------------------------- -* Hamming code table -* 0 1 2 3 4 5 6 7 8 9 A B C D E F */// -// lets move this out of progmem, we need it to be fast -const unsigned char HamTab[] = -{ 0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA}; +* Reverse bytes +*/ +const uint8_t ReverseByteTab[256] = { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, + 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, + 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, + 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, + 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, + 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, + 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, + 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, + 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, + 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, + 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, + 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, + 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, + 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, + 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, + 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, + 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +}; /*------------------------------------------- -* Hamming decode table +* Odd parity table */ -const unsigned char DehamTable[] = { - 0x01,0x80,0x01,0x01,0x80,0x00,0x01,0x80, - 0x80,0x02,0x01,0x80,0x0A,0x80,0x80,0x07, - 0x80,0x00,0x01,0x80,0x00,0x00,0x80,0x00, - 0x06,0x80,0x80,0x0B,0x80,0x00,0x03,0x80, - 0x80,0x0C,0x01,0x80,0x04,0x80,0x80,0x07, - 0x06,0x80,0x80,0x07,0x80,0x07,0x07,0x07, - 0x06,0x80,0x80,0x05,0x80,0x00,0x0D,0x80, - 0x06,0x06,0x06,0x80,0x06,0x80,0x80,0x07, - 0x80,0x02,0x01,0x80,0x04,0x80,0x80,0x09, - 0x02,0x02,0x80,0x02,0x80,0x02,0x03,0x80, - 0x08,0x80,0x80,0x05,0x80,0x00,0x03,0x80, - 0x80,0x02,0x03,0x80,0x03,0x80,0x03,0x03, - 0x04,0x80,0x80,0x05,0x04,0x04,0x04,0x80, - 0x80,0x02,0x0F,0x80,0x04,0x80,0x80,0x07, - 0x80,0x05,0x05,0x05,0x04,0x80,0x80,0x05, - 0x06,0x80,0x80,0x05,0x80,0x0E,0x03,0x80, - 0x80,0x0C,0x01,0x80,0x0A,0x80,0x80,0x09, - 0x0A,0x80,0x80,0x0B,0x0A,0x0A,0x0A,0x80, - 0x08,0x80,0x80,0x0B,0x80,0x00,0x0D,0x80, - 0x80,0x0B,0x0B,0x0B,0x0A,0x80,0x80,0x0B, - 0x0C,0x0C,0x80,0x0C,0x80,0x0C,0x0D,0x80, - 0x80,0x0C,0x0F,0x80,0x0A,0x80,0x80,0x07, - 0x80,0x0C,0x0D,0x80,0x0D,0x80,0x0D,0x0D, - 0x06,0x80,0x80,0x0B,0x80,0x0E,0x0D,0x80, - 0x08,0x80,0x80,0x09,0x80,0x09,0x09,0x09, - 0x80,0x02,0x0F,0x80,0x0A,0x80,0x80,0x09, - 0x08,0x08,0x08,0x80,0x08,0x80,0x80,0x09, - 0x08,0x80,0x80,0x0B,0x80,0x0E,0x03,0x80, - 0x80,0x0C,0x0F,0x80,0x04,0x80,0x80,0x09, - 0x0F,0x80,0x0F,0x0F,0x80,0x0E,0x0F,0x80, - 0x08,0x80,0x80,0x05,0x80,0x0E,0x0D,0x80, - 0x80,0x0E,0x0F,0x80,0x0E,0x0E,0x80,0x0E}; +const uint8_t OddParityTable[128] = { + 0x80,0x01,0x02,0x83,0x04,0x85,0x86,0x07, + 0x08,0x89,0x8A,0x0B,0x8C,0x0D,0x0E,0x8F, + 0x10,0x91,0x92,0x13,0x94,0x15,0x16,0x97, + 0x98,0x19,0x1A,0x9B,0x1C,0x9D,0x9E,0x1F, + 0x20,0xA1,0xA2,0x23,0xA4,0x25,0x26,0xA7, + 0xA8,0x29,0x2A,0xAB,0x2C,0xAD,0xAE,0x2F, + 0xB0,0x31,0x32,0xB3,0x34,0xB5,0xB6,0x37, + 0x38,0xB9,0xBA,0x3B,0xBC,0x3D,0x3E,0xBF, + 0x40,0xC1,0xC2,0x43,0xC4,0x45,0x46,0xC7, + 0xC8,0x49,0x4A,0xCB,0x4C,0xCD,0xCE,0x4F, + 0xD0,0x51,0x52,0xD3,0x54,0xD5,0xD6,0x57, + 0x58,0xD9,0xDA,0x5B,0xDC,0x5D,0x5E,0xDF, + 0xE0,0x61,0x62,0xE3,0x64,0xE5,0xE6,0x67, + 0x68,0xE9,0xEA,0x6B,0xEC,0x6D,0x6E,0xEF, + 0x70,0xF1,0xF2,0x73,0xF4,0x75,0x76,0xF7, + 0xF8,0x79,0x7A,0xFB,0x7C,0xFD,0xFE,0x7F}; + /*------------------------------------------- -*/ +* Hamming 8/4 encode table +* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +const uint8_t Hamming8EncodeTable[16] = { + 0x15,0x02,0x49,0x5E,0x64,0x73,0x38,0x2F,0xD0,0xC7,0x8C,0x9B,0xA1,0xB6,0xFD,0xEA}; -// Four bit reverse nybble -unsigned char BitRev[16] = { - '\x0','\x8','\x4','\xc', - '\x2','\xa','\x6','\xe', - '\x1','\x9','\x5','\xd', - '\x3','\xb','\x7','\xf' +/*------------------------------------------- +* Hamming 8/4 decode table +*/ +const uint8_t Hamming8DecodeTable[256] = { + 0x01,0x80,0x01,0x01,0x80,0x00,0x01,0x80, + 0x80,0x02,0x01,0x80,0x0A,0x80,0x80,0x07, + 0x80,0x00,0x01,0x80,0x00,0x00,0x80,0x00, + 0x06,0x80,0x80,0x0B,0x80,0x00,0x03,0x80, + 0x80,0x0C,0x01,0x80,0x04,0x80,0x80,0x07, + 0x06,0x80,0x80,0x07,0x80,0x07,0x07,0x07, + 0x06,0x80,0x80,0x05,0x80,0x00,0x0D,0x80, + 0x06,0x06,0x06,0x80,0x06,0x80,0x80,0x07, + 0x80,0x02,0x01,0x80,0x04,0x80,0x80,0x09, + 0x02,0x02,0x80,0x02,0x80,0x02,0x03,0x80, + 0x08,0x80,0x80,0x05,0x80,0x00,0x03,0x80, + 0x80,0x02,0x03,0x80,0x03,0x80,0x03,0x03, + 0x04,0x80,0x80,0x05,0x04,0x04,0x04,0x80, + 0x80,0x02,0x0F,0x80,0x04,0x80,0x80,0x07, + 0x80,0x05,0x05,0x05,0x04,0x80,0x80,0x05, + 0x06,0x80,0x80,0x05,0x80,0x0E,0x03,0x80, + 0x80,0x0C,0x01,0x80,0x0A,0x80,0x80,0x09, + 0x0A,0x80,0x80,0x0B,0x0A,0x0A,0x0A,0x80, + 0x08,0x80,0x80,0x0B,0x80,0x00,0x0D,0x80, + 0x80,0x0B,0x0B,0x0B,0x0A,0x80,0x80,0x0B, + 0x0C,0x0C,0x80,0x0C,0x80,0x0C,0x0D,0x80, + 0x80,0x0C,0x0F,0x80,0x0A,0x80,0x80,0x07, + 0x80,0x0C,0x0D,0x80,0x0D,0x80,0x0D,0x0D, + 0x06,0x80,0x80,0x0B,0x80,0x0E,0x0D,0x80, + 0x08,0x80,0x80,0x09,0x80,0x09,0x09,0x09, + 0x80,0x02,0x0F,0x80,0x0A,0x80,0x80,0x09, + 0x08,0x08,0x08,0x80,0x08,0x80,0x80,0x09, + 0x08,0x80,0x80,0x0B,0x80,0x0E,0x03,0x80, + 0x80,0x0C,0x0F,0x80,0x04,0x80,0x80,0x09, + 0x0F,0x80,0x0F,0x0F,0x80,0x0E,0x0F,0x80, + 0x08,0x80,0x80,0x05,0x80,0x0E,0x0D,0x80, + 0x80,0x0E,0x0F,0x80,0x0E,0x0E,0x80,0x0E }; -/*------------------------------------------ -*Mrag Table. Contains pairs of bytes for -*Mrags for lines 0-27 in mags 1-8. -* While this is convenient it is a bit extravagant and might be a candidate for coding -* because it is a simple bit manipulation task. +/*------------------------------------------- +* Hamming 24/18 encode tables */ -#define LenMragMagEntry 56 - -const unsigned char MragTable[8][LenMragMagEntry] = { -/*Mag 1 */ - {0x02,0x15,0xc7,0x15,0x02,0x02,0xc7,0x02, - 0x02,0x49,0xc7,0x49,0x02,0x5e,0xc7,0x5e, - 0x02,0x64,0xc7,0x64,0x02,0x73,0xc7,0x73, - 0x02,0x38,0xc7,0x38,0x02,0x2f,0xc7,0x2f, - 0x02,0xd0,0xc7,0xd0,0x02,0xc7,0xc7,0xc7, - 0x02,0x8c,0xc7,0x8c,0x02,0x9b,0xc7,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 2 */ - {0x49,0x15,0x8c,0x15,0x49,0x02,0x8c,0x02, - 0x49,0x49,0x8c,0x49,0x49,0x5e,0x8c,0x5e, - 0x49,0x64,0x8c,0x64,0x49,0x73,0x8c,0x73, - 0x49,0x38,0x8c,0x38,0x49,0x2f,0x8c,0x2f, - 0x49,0xd0,0x8c,0xd0,0x49,0xc7,0x8c,0xc7, - 0x49,0x8c,0x8c,0x8c,0x49,0x9b,0x8c,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 3*/ - {0x5e,0x15,0x9b,0x15,0x5e,0x02,0x9b,0x02, - 0x5e,0x49,0x9b,0x49,0x5e,0x5e,0x9b,0x5e, - 0x5e,0x64,0x9b,0x64,0x5e,0x73,0x9b,0x73, - 0x5e,0x38,0x9b,0x38,0x5e,0x2f,0x9b,0x2f, - 0x5e,0xd0,0x9b,0xd0,0x5e,0xc7,0x9b,0xc7, - 0x5e,0x8c,0x9b,0x8c,0x5e,0x9b,0x9b,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 4*/ - {0x64,0x15,0xa1,0x15,0x64,0x02,0xa1,0x02, - 0x64,0x49,0xa1,0x49,0x64,0x5e,0xa1,0x5e, - 0x64,0x64,0xa1,0x64,0x64,0x73,0xa1,0x73, - 0x64,0x38,0xa1,0x38,0x64,0x2f,0xa1,0x2f, - 0x64,0xd0,0xa1,0xd0,0x64,0xc7,0xa1,0xc7, - 0x64,0x8c,0xa1,0x8c,0x64,0x9b,0xa1,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 5 */ - {0x73,0x15,0xb6,0x15,0x73,0x02,0xb6,0x02, - 0x73,0x49,0xb6,0x49,0x73,0x5e,0xb6,0x5e, - 0x73,0x64,0xb6,0x64,0x73,0x73,0xb6,0x73, - 0x73,0x38,0xb6,0x38,0x73,0x2f,0xb6,0x2f, - 0x73,0xd0,0xb6,0xd0,0x73,0xc7,0xb6,0xc7, - 0x73,0x8c,0xb6,0x8c,0x73,0x9b,0xb6,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 6 */ - {0x38,0x15,0xfd,0x15,0x38,0x02,0xfd,0x02, - 0x38,0x49,0xfd,0x49,0x38,0x5e,0xfd,0x5e, - 0x38,0x64,0xfd,0x64,0x38,0x73,0xfd,0x73, - 0x38,0x38,0xfd,0x38,0x38,0x2f,0xfd,0x2f, - 0x38,0xd0,0xfd,0xd0,0x38,0xc7,0xfd,0xc7, - 0x38,0x8c,0xfd,0x8c,0x38,0x9b,0xfd,0x9b, - 0,0,0,0,0,0,0,0}, - -/*Mag 7 */ - {0x2f,0x15,0xea,0x15,0x2f,0x02,0xea,0x02, - 0x2f,0x49,0xea,0x49,0x2f,0x5e,0xea,0x5e, - 0x2f,0x64,0xea,0x64,0x2f,0x73,0xea,0x73, - 0x2f,0x38,0xea,0x38,0x2f,0x2f,0xea,0x2f, - 0x2f,0xd0,0xea,0xd0,0x2f,0xc7,0xea,0xc7, - 0x2f,0x8c,0xea,0x8c,0x2f,0x9b,0xea,0x9b, - 0,0,0,0,0,0,0,0}, +const uint8_t Hamming24EncodeTable0[256] = { + 0x8b,0x8c,0x92,0x95,0xa1,0xa6,0xb8,0xbf, + 0xc0,0xc7,0xd9,0xde,0xea,0xed,0xf3,0xf4, + 0x0a,0x0d,0x13,0x14,0x20,0x27,0x39,0x3e, + 0x41,0x46,0x58,0x5f,0x6b,0x6c,0x72,0x75, + 0x09,0x0e,0x10,0x17,0x23,0x24,0x3a,0x3d, + 0x42,0x45,0x5b,0x5c,0x68,0x6f,0x71,0x76, + 0x88,0x8f,0x91,0x96,0xa2,0xa5,0xbb,0xbc, + 0xc3,0xc4,0xda,0xdd,0xe9,0xee,0xf0,0xf7, + 0x08,0x0f,0x11,0x16,0x22,0x25,0x3b,0x3c, + 0x43,0x44,0x5a,0x5d,0x69,0x6e,0x70,0x77, + 0x89,0x8e,0x90,0x97,0xa3,0xa4,0xba,0xbd, + 0xc2,0xc5,0xdb,0xdc,0xe8,0xef,0xf1,0xf6, + 0x8a,0x8d,0x93,0x94,0xa0,0xa7,0xb9,0xbe, + 0xc1,0xc6,0xd8,0xdf,0xeb,0xec,0xf2,0xf5, + 0x0b,0x0c,0x12,0x15,0x21,0x26,0x38,0x3f, + 0x40,0x47,0x59,0x5e,0x6a,0x6d,0x73,0x74, + 0x03,0x04,0x1a,0x1d,0x29,0x2e,0x30,0x37, + 0x48,0x4f,0x51,0x56,0x62,0x65,0x7b,0x7c, + 0x82,0x85,0x9b,0x9c,0xa8,0xaf,0xb1,0xb6, + 0xc9,0xce,0xd0,0xd7,0xe3,0xe4,0xfa,0xfd, + 0x81,0x86,0x98,0x9f,0xab,0xac,0xb2,0xb5, + 0xca,0xcd,0xd3,0xd4,0xe0,0xe7,0xf9,0xfe, + 0x00,0x07,0x19,0x1e,0x2a,0x2d,0x33,0x34, + 0x4b,0x4c,0x52,0x55,0x61,0x66,0x78,0x7f, + 0x80,0x87,0x99,0x9e,0xaa,0xad,0xb3,0xb4, + 0xcb,0xcc,0xd2,0xd5,0xe1,0xe6,0xf8,0xff, + 0x01,0x06,0x18,0x1f,0x2b,0x2c,0x32,0x35, + 0x4a,0x4d,0x53,0x54,0x60,0x67,0x79,0x7e, + 0x02,0x05,0x1b,0x1c,0x28,0x2f,0x31,0x36, + 0x49,0x4e,0x50,0x57,0x63,0x64,0x7a,0x7d, + 0x83,0x84,0x9a,0x9d,0xa9,0xae,0xb0,0xb7, + 0xc8,0xcf,0xd1,0xd6,0xe2,0xe5,0xfb,0xfc +}; -/*Mag 8 */ - {0x15,0x15,0xd0,0x15,0x15,0x02,0xd0,0x02, - 0x15,0x49,0xd0,0x49,0x15,0x5e,0xd0,0x5e, - 0x15,0x64,0xd0,0x64,0x15,0x73,0xd0,0x73, - 0x15,0x38,0xd0,0x38,0x15,0x2f,0xd0,0x2f, - 0x15,0xd0,0xd0,0xd0,0x15,0xc7,0xd0,0xc7, - 0x15,0x8c,0xd0,0x8c,0x15,0x9b,0xd0,0x9b, - 0,0,0,0,0,0,0,0} +const uint8_t Hamming24EncodeTable1[256] = { + 0x00,0x89,0x8a,0x03,0x8b,0x02,0x01,0x88, + 0x01,0x88,0x8b,0x02,0x8a,0x03,0x00,0x89, + 0x02,0x8b,0x88,0x01,0x89,0x00,0x03,0x8a, + 0x03,0x8a,0x89,0x00,0x88,0x01,0x02,0x8b, + 0x03,0x8a,0x89,0x00,0x88,0x01,0x02,0x8b, + 0x02,0x8b,0x88,0x01,0x89,0x00,0x03,0x8a, + 0x01,0x88,0x8b,0x02,0x8a,0x03,0x00,0x89, + 0x00,0x89,0x8a,0x03,0x8b,0x02,0x01,0x88, + 0x08,0x81,0x82,0x0b,0x83,0x0a,0x09,0x80, + 0x09,0x80,0x83,0x0a,0x82,0x0b,0x08,0x81, + 0x0a,0x83,0x80,0x09,0x81,0x08,0x0b,0x82, + 0x0b,0x82,0x81,0x08,0x80,0x09,0x0a,0x83, + 0x0b,0x82,0x81,0x08,0x80,0x09,0x0a,0x83, + 0x0a,0x83,0x80,0x09,0x81,0x08,0x0b,0x82, + 0x09,0x80,0x83,0x0a,0x82,0x0b,0x08,0x81, + 0x08,0x81,0x82,0x0b,0x83,0x0a,0x09,0x80, + 0x09,0x80,0x83,0x0a,0x82,0x0b,0x08,0x81, + 0x08,0x81,0x82,0x0b,0x83,0x0a,0x09,0x80, + 0x0b,0x82,0x81,0x08,0x80,0x09,0x0a,0x83, + 0x0a,0x83,0x80,0x09,0x81,0x08,0x0b,0x82, + 0x0a,0x83,0x80,0x09,0x81,0x08,0x0b,0x82, + 0x0b,0x82,0x81,0x08,0x80,0x09,0x0a,0x83, + 0x08,0x81,0x82,0x0b,0x83,0x0a,0x09,0x80, + 0x09,0x80,0x83,0x0a,0x82,0x0b,0x08,0x81, + 0x01,0x88,0x8b,0x02,0x8a,0x03,0x00,0x89, + 0x00,0x89,0x8a,0x03,0x8b,0x02,0x01,0x88, + 0x03,0x8a,0x89,0x00,0x88,0x01,0x02,0x8b, + 0x02,0x8b,0x88,0x01,0x89,0x00,0x03,0x8a, + 0x02,0x8b,0x88,0x01,0x89,0x00,0x03,0x8a, + 0x03,0x8a,0x89,0x00,0x88,0x01,0x02,0x8b, + 0x00,0x89,0x8a,0x03,0x8b,0x02,0x01,0x88, + 0x01,0x88,0x8b,0x02,0x8a,0x03,0x00,0x89 +}; +const uint8_t Hamming24EncodeTable2[4] = { + 0x00,0x0a,0x0b,0x01 }; - -/*---------------------------------------------- -*------------------------------------------ -*CRC lookup tables -*high byte table -*/ -const unsigned char TH[] = { - 0x00,0x52,0x25,0x77,0x4A,0x18,0x6F,0x3D, - 0x94,0xC6,0xB1,0xE3,0xDE,0x8C,0xFB,0xA9, - 0x28,0x7A,0x0D,0x5F,0x62,0x30,0x47,0x15, - 0xBC,0xEE,0x99,0xCB,0xF6,0xA4,0xD3,0x81, - 0x50,0x02,0x75,0x27,0x1A,0x48,0x3F,0x6D, - 0xC4,0x96,0xE1,0xB3,0x8E,0xDC,0xAB,0xF9, - 0x78,0x2A,0x5D,0x0F,0x32,0x60,0x17,0x45, - 0xEC,0xBE,0xC9,0x9B,0xA6,0xF4,0x83,0xD1, - 0xA0,0xF2,0x85,0xD7,0xEA,0xB8,0xCF,0x9D, - 0x34,0x66,0x11,0x43,0x7E,0x2C,0x5B,0x09, - 0x88,0xDA,0xAD,0xFF,0xC2,0x90,0xE7,0xB5, - 0x1C,0x4E,0x39,0x6B,0x56,0x04,0x73,0x21, - 0xF0,0xA2,0xD5,0x87,0xBA,0xE8,0x9F,0xCD, - 0x64,0x36,0x41,0x13,0x2E,0x7C,0x0B,0x59, - 0xD8,0x8A,0xFD,0xAF,0x92,0xC0,0xB7,0xE5, - 0x4C,0x1E,0x69,0x3B,0x06,0x54,0x23,0x71, - 0x40,0x12,0x65,0x37,0x0A,0x58,0x2F,0x7D, - 0xD4,0x86,0xF1,0xA3,0x9E,0xCC,0xBB,0xE9, - 0x68,0x3A,0x4D,0x1F,0x22,0x70,0x07,0x55, - 0xFC,0xAE,0xD9,0x8B,0xB6,0xE4,0x93,0xC1, - 0x10,0x42,0x35,0x67,0x5A,0x08,0x7F,0x2D, - 0x84,0xD6,0xA1,0xF3,0xCE,0x9C,0xEB,0xB9, - 0x38,0x6A,0x1D,0x4F,0x72,0x20,0x57,0x05, - 0xAC,0xFE,0x89,0xDB,0xE6,0xB4,0xC3,0x91, - 0xE0,0xB2,0xC5,0x97,0xAA,0xF8,0x8F,0xDD, - 0x74,0x26,0x51,0x03,0x3E,0x6C,0x1B,0x49, - 0xC8,0x9A,0xED,0xBF,0x82,0xD0,0xA7,0xF5, - 0x5C,0x0E,0x79,0x2B,0x16,0x44,0x33,0x61, - 0xB0,0xE2,0x95,0xC7,0xFA,0xA8,0xDF,0x8D, - 0x24,0x76,0x01,0x53,0x6E,0x3C,0x4B,0x19, - 0x98,0xCA,0xBD,0xEF,0xD2,0x80,0xF7,0xA5, - 0x0C,0x5E,0x29,0x7B,0x46,0x14,0x63,0x31}; -/*low byte table -*/ -const unsigned char TL[] = { - 0x00,0x88,0x02,0x8A,0x04,0x8C,0x06,0x8E, - 0x08,0x80,0x0A,0x82,0x0C,0x84,0x0E,0x86, - 0x11,0x99,0x13,0x9B,0x15,0x9D,0x17,0x9F, - 0x19,0x91,0x1B,0x93,0x1D,0x95,0x1F,0x97, - 0x22,0xAA,0x20,0xA8,0x26,0xAE,0x24,0xAC, - 0x2A,0xA2,0x28,0xA0,0x2E,0xA6,0x2C,0xA4, - 0x33,0xBB,0x31,0xB9,0x37,0xBF,0x35,0xBD, - 0x3B,0xB3,0x39,0xB1,0x3F,0xB7,0x3D,0xB5, - 0x44,0xCC,0x46,0xCE,0x40,0xC8,0x42,0xCA, - 0x4C,0xC4,0x4E,0xC6,0x48,0xC0,0x4A,0xC2, - 0x55,0xDD,0x57,0xDF,0x51,0xD9,0x53,0xDB, - 0x5D,0xD5,0x5F,0xD7,0x59,0xD1,0x5B,0xD3, - 0x66,0xEE,0x64,0xEC,0x62,0xEA,0x60,0xE8, - 0x6E,0xE6,0x6C,0xE4,0x6A,0xE2,0x68,0xE0, - 0x77,0xFF,0x75,0xFD,0x73,0xFB,0x71,0xF9, - 0x7F,0xF7,0x7D,0xF5,0x7B,0xF3,0x79,0xF1, - 0x89,0x01,0x8B,0x03,0x8D,0x05,0x8F,0x07, - 0x81,0x09,0x83,0x0B,0x85,0x0D,0x87,0x0F, - 0x98,0x10,0x9A,0x12,0x9C,0x14,0x9E,0x16, - 0x90,0x18,0x92,0x1A,0x94,0x1C,0x96,0x1E, - 0xAB,0x23,0xA9,0x21,0xAF,0x27,0xAD,0x25, - 0xA3,0x2B,0xA1,0x29,0xA7,0x2F,0xA5,0x2D, - 0xBA,0x32,0xB8,0x30,0xBE,0x36,0xBC,0x34, - 0xB2,0x3A,0xB0,0x38,0xB6,0x3E,0xB4,0x3C, - 0xCD,0x45,0xCF,0x47,0xC9,0x41,0xCB,0x43, - 0xC5,0x4D,0xC7,0x4F,0xC1,0x49,0xC3,0x4B, - 0xDC,0x54,0xDE,0x56,0xD8,0x50,0xDA,0x52, - 0xD4,0x5C,0xD6,0x5E,0xD0,0x58,0xD2,0x5A, - 0xEF,0x67,0xED,0x65,0xEB,0x63,0xE9,0x61, - 0xE7,0x6F,0xE5,0x6D,0xE3,0x6B,0xE1,0x69, - 0xFE,0x76,0xFC,0x74,0xFA,0x72,0xF8,0x70, - 0xF6,0x7E,0xF4,0x7C,0xF2,0x7A,0xF0,0x78}; -/*---------------------------------------------------------------------*/ +const uint8_t Hamming24ParityTable[3][256] = { + { + 0x00,0x21,0x22,0x03,0x23,0x02,0x01,0x20, + 0x24,0x05,0x06,0x27,0x07,0x26,0x25,0x04, + 0x25,0x04,0x07,0x26,0x06,0x27,0x24,0x05, + 0x01,0x20,0x23,0x02,0x22,0x03,0x00,0x21, + 0x26,0x07,0x04,0x25,0x05,0x24,0x27,0x06, + 0x02,0x23,0x20,0x01,0x21,0x00,0x03,0x22, + 0x03,0x22,0x21,0x00,0x20,0x01,0x02,0x23, + 0x27,0x06,0x05,0x24,0x04,0x25,0x26,0x07, + 0x27,0x06,0x05,0x24,0x04,0x25,0x26,0x07, + 0x03,0x22,0x21,0x00,0x20,0x01,0x02,0x23, + 0x02,0x23,0x20,0x01,0x21,0x00,0x03,0x22, + 0x26,0x07,0x04,0x25,0x05,0x24,0x27,0x06, + 0x01,0x20,0x23,0x02,0x22,0x03,0x00,0x21, + 0x25,0x04,0x07,0x26,0x06,0x27,0x24,0x05, + 0x24,0x05,0x06,0x27,0x07,0x26,0x25,0x04, + 0x00,0x21,0x22,0x03,0x23,0x02,0x01,0x20, + 0x28,0x09,0x0a,0x2b,0x0b,0x2a,0x29,0x08, + 0x0c,0x2d,0x2e,0x0f,0x2f,0x0e,0x0d,0x2c, + 0x0d,0x2c,0x2f,0x0e,0x2e,0x0f,0x0c,0x2d, + 0x29,0x08,0x0b,0x2a,0x0a,0x2b,0x28,0x09, + 0x0e,0x2f,0x2c,0x0d,0x2d,0x0c,0x0f,0x2e, + 0x2a,0x0b,0x08,0x29,0x09,0x28,0x2b,0x0a, + 0x2b,0x0a,0x09,0x28,0x08,0x29,0x2a,0x0b, + 0x0f,0x2e,0x2d,0x0c,0x2c,0x0d,0x0e,0x2f, + 0x0f,0x2e,0x2d,0x0c,0x2c,0x0d,0x0e,0x2f, + 0x2b,0x0a,0x09,0x28,0x08,0x29,0x2a,0x0b, + 0x2a,0x0b,0x08,0x29,0x09,0x28,0x2b,0x0a, + 0x0e,0x2f,0x2c,0x0d,0x2d,0x0c,0x0f,0x2e, + 0x29,0x08,0x0b,0x2a,0x0a,0x2b,0x28,0x09, + 0x0d,0x2c,0x2f,0x0e,0x2e,0x0f,0x0c,0x2d, + 0x0c,0x2d,0x2e,0x0f,0x2f,0x0e,0x0d,0x2c, + 0x28,0x09,0x0a,0x2b,0x0b,0x2a,0x29,0x08 + }, { + 0x00,0x29,0x2a,0x03,0x2b,0x02,0x01,0x28, + 0x2c,0x05,0x06,0x2f,0x07,0x2e,0x2d,0x04, + 0x2d,0x04,0x07,0x2e,0x06,0x2f,0x2c,0x05, + 0x01,0x28,0x2b,0x02,0x2a,0x03,0x00,0x29, + 0x2e,0x07,0x04,0x2d,0x05,0x2c,0x2f,0x06, + 0x02,0x2b,0x28,0x01,0x29,0x00,0x03,0x2a, + 0x03,0x2a,0x29,0x00,0x28,0x01,0x02,0x2b, + 0x2f,0x06,0x05,0x2c,0x04,0x2d,0x2e,0x07, + 0x2f,0x06,0x05,0x2c,0x04,0x2d,0x2e,0x07, + 0x03,0x2a,0x29,0x00,0x28,0x01,0x02,0x2b, + 0x02,0x2b,0x28,0x01,0x29,0x00,0x03,0x2a, + 0x2e,0x07,0x04,0x2d,0x05,0x2c,0x2f,0x06, + 0x01,0x28,0x2b,0x02,0x2a,0x03,0x00,0x29, + 0x2d,0x04,0x07,0x2e,0x06,0x2f,0x2c,0x05, + 0x2c,0x05,0x06,0x2f,0x07,0x2e,0x2d,0x04, + 0x00,0x29,0x2a,0x03,0x2b,0x02,0x01,0x28, + 0x30,0x19,0x1a,0x33,0x1b,0x32,0x31,0x18, + 0x1c,0x35,0x36,0x1f,0x37,0x1e,0x1d,0x34, + 0x1d,0x34,0x37,0x1e,0x36,0x1f,0x1c,0x35, + 0x31,0x18,0x1b,0x32,0x1a,0x33,0x30,0x19, + 0x1e,0x37,0x34,0x1d,0x35,0x1c,0x1f,0x36, + 0x32,0x1b,0x18,0x31,0x19,0x30,0x33,0x1a, + 0x33,0x1a,0x19,0x30,0x18,0x31,0x32,0x1b, + 0x1f,0x36,0x35,0x1c,0x34,0x1d,0x1e,0x37, + 0x1f,0x36,0x35,0x1c,0x34,0x1d,0x1e,0x37, + 0x33,0x1a,0x19,0x30,0x18,0x31,0x32,0x1b, + 0x32,0x1b,0x18,0x31,0x19,0x30,0x33,0x1a, + 0x1e,0x37,0x34,0x1d,0x35,0x1c,0x1f,0x36, + 0x31,0x18,0x1b,0x32,0x1a,0x33,0x30,0x19, + 0x1d,0x34,0x37,0x1e,0x36,0x1f,0x1c,0x35, + 0x1c,0x35,0x36,0x1f,0x37,0x1e,0x1d,0x34, + 0x30,0x19,0x1a,0x33,0x1b,0x32,0x31,0x18 + }, { + 0x3f,0x0e,0x0d,0x3c,0x0c,0x3d,0x3e,0x0f, + 0x0b,0x3a,0x39,0x08,0x38,0x09,0x0a,0x3b, + 0x0a,0x3b,0x38,0x09,0x39,0x08,0x0b,0x3a, + 0x3e,0x0f,0x0c,0x3d,0x0d,0x3c,0x3f,0x0e, + 0x09,0x38,0x3b,0x0a,0x3a,0x0b,0x08,0x39, + 0x3d,0x0c,0x0f,0x3e,0x0e,0x3f,0x3c,0x0d, + 0x3c,0x0d,0x0e,0x3f,0x0f,0x3e,0x3d,0x0c, + 0x08,0x39,0x3a,0x0b,0x3b,0x0a,0x09,0x38, + 0x08,0x39,0x3a,0x0b,0x3b,0x0a,0x09,0x38, + 0x3c,0x0d,0x0e,0x3f,0x0f,0x3e,0x3d,0x0c, + 0x3d,0x0c,0x0f,0x3e,0x0e,0x3f,0x3c,0x0d, + 0x09,0x38,0x3b,0x0a,0x3a,0x0b,0x08,0x39, + 0x3e,0x0f,0x0c,0x3d,0x0d,0x3c,0x3f,0x0e, + 0x0a,0x3b,0x38,0x09,0x39,0x08,0x0b,0x3a, + 0x0b,0x3a,0x39,0x08,0x38,0x09,0x0a,0x3b, + 0x3f,0x0e,0x0d,0x3c,0x0c,0x3d,0x3e,0x0f, + 0x1f,0x2e,0x2d,0x1c,0x2c,0x1d,0x1e,0x2f, + 0x2b,0x1a,0x19,0x28,0x18,0x29,0x2a,0x1b, + 0x2a,0x1b,0x18,0x29,0x19,0x28,0x2b,0x1a, + 0x1e,0x2f,0x2c,0x1d,0x2d,0x1c,0x1f,0x2e, + 0x29,0x18,0x1b,0x2a,0x1a,0x2b,0x28,0x19, + 0x1d,0x2c,0x2f,0x1e,0x2e,0x1f,0x1c,0x2d, + 0x1c,0x2d,0x2e,0x1f,0x2f,0x1e,0x1d,0x2c, + 0x28,0x19,0x1a,0x2b,0x1b,0x2a,0x29,0x18, + 0x28,0x19,0x1a,0x2b,0x1b,0x2a,0x29,0x18, + 0x1c,0x2d,0x2e,0x1f,0x2f,0x1e,0x1d,0x2c, + 0x1d,0x2c,0x2f,0x1e,0x2e,0x1f,0x1c,0x2d, + 0x29,0x18,0x1b,0x2a,0x1a,0x2b,0x28,0x19, + 0x1e,0x2f,0x2c,0x1d,0x2d,0x1c,0x1f,0x2e, + 0x2a,0x1b,0x18,0x29,0x19,0x28,0x2b,0x1a, + 0x2b,0x1a,0x19,0x28,0x18,0x29,0x2a,0x1b, + 0x1f,0x2e,0x2d,0x1c,0x2c,0x1d,0x1e,0x2f + } +}; diff --git a/tables.h b/tables.h index aa294fc..0b9ec37 100644 --- a/tables.h +++ b/tables.h @@ -21,150 +21,23 @@ * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. - *************************************************************************** **/ + *****************************************************************************/ #ifndef _TABLES_H_ #define _TABLES_H_ +#include - -/*-------------------------------------- -*TABLES ---------------------------------------*/ -/* Parity table. -* Use 1st half to add odd parity, -* Use 2nd half to add even parity -* Both halves to remove odd parity - signals error if -ve. -*/ -extern const unsigned char ParTab[]; -/*------------------------------------------- -* Hamming code table -* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ -extern const unsigned char HamTab[]; -/*-------------------------------------------*/ -extern const unsigned char DehamTable[]; -/* Hamming decode table -DHMTBL 0x01,0x80,0x01,0x01,0x80,0x00,0x01,0x80 - 0x80,0x02,0x01,0x80,0x0A,0x80,0x80,0x07 - 0x80,0x00,0x01,0x80,0x00,0x00,0x80,0x00 - 0x06,0x80,0x80,0x0B,0x80,0x00,0x03,0x80 - 0x80,0x0C,0x01,0x80,0x04,0x80,0x80,0x07 - 0x06,0x80,0x80,0x07,0x80,0x07,0x07,0x07 - 0x06,0x80,0x80,0x05,0x80,0x00,0x0D,0x80 - 0x06,0x06,0x06,0x80,0x06,0x80,0x80,0x07 - 0x80,0x02,0x01,0x80,0x04,0x80,0x80,0x09 - 0x02,0x02,0x80,0x02,0x80,0x02,0x03,0x80 - 0x08,0x80,0x80,0x05,0x80,0x00,0x03,0x80 - 0x80,0x02,0x03,0x80,0x03,0x80,0x03,0x03 - 0x04,0x80,0x80,0x05,0x04,0x04,0x04,0x80 - 0x80,0x02,0x0F,0x80,0x04,0x80,0x80,0x07 - 0x80,0x05,0x05,0x05,0x04,0x80,0x80,0x05 - 0x06,0x80,0x80,0x05,0x80,0x0E,0x03,0x80 - 0x80,0x0C,0x01,0x80,0x0A,0x80,0x80,0x09 - 0x0A,0x80,0x80,0x0B,0x0A,0x0A,0x0A,0x80 - 0x08,0x80,0x80,0x0B,0x80,0x00,0x0D,0x80 - 0x80,0x0B,0x0B,0x0B,0x0A,0x80,0x80,0x0B - 0x0C,0x0C,0x80,0x0C,0x80,0x0C,0x0D,0x80 - 0x80,0x0C,0x0F,0x80,0x0A,0x80,0x80,0x07 - 0x80,0x0C,0x0D,0x80,0x0D,0x80,0x0D,0x0D - 0x06,0x80,0x80,0x0B,0x80,0x0E,0x0D,0x80 - 0x08,0x80,0x80,0x09,0x80,0x09,0x09,0x09 - 0x80,0x02,0x0F,0x80,0x0A,0x80,0x80,0x09 - 0x08,0x08,0x08,0x80,0x08,0x80,0x80,0x09 - 0x08,0x80,0x80,0x0B,0x80,0x0E,0x03,0x80 - 0x80,0x0C,0x0F,0x80,0x04,0x80,0x80,0x09 - 0x0F,0x80,0x0F,0x0F,0x80,0x0E,0x0F,0x80 - 0x08,0x80,0x80,0x05,0x80,0x0E,0x0D,0x80 - 0x80,0x0E,0x0F,0x80,0x0E,0x0E,0x80,0x0E -*------------------------------------------- -*/ +extern const uint8_t ReverseByteTab[256]; -// Four bit reverse nybble -extern unsigned char BitRev[16]; +extern const uint8_t OddParityTable[128]; -/*------------------------------------------ -*Mrag Table. Contains pairs of bytes for -*Mrags for lines 0-27 in mags 1-8. -* While this is convenient it is a bit extravagant and might be a candidate for coding -* because it is a simple bit manipulation task. -*/ -#define LenMragMagEntry 56 +extern const uint8_t Hamming8EncodeTable[16]; -extern const unsigned char MragTable[8][LenMragMagEntry]; -/*----------------------------------------------*/ -extern const unsigned char TL[]; -extern const unsigned char TH[]; -/*------------------------------------------*/ -/* -*CRC lookup tables -*high byte table +extern const uint8_t Hamming8DecodeTable[256]; -TH 0x00,0x52,0x25,0x77,0x4A,0x18,0x6F,0x3D - 0x94,0xC6,0xB1,0xE3,0xDE,0x8C,0xFB,0xA9 - 0x28,0x7A,0x0D,0x5F,0x62,0x30,0x47,0x15 - 0xBC,0xEE,0x99,0xCB,0xF6,0xA4,0xD3,0x81 - 0x50,0x02,0x75,0x27,0x1A,0x48,0x3F,0x6D - 0xC4,0x96,0xE1,0xB3,0x8E,0xDC,0xAB,0xF9 - 0x78,0x2A,0x5D,0x0F,0x32,0x60,0x17,0x45 - 0xEC,0xBE,0xC9,0x9B,0xA6,0xF4,0x83,0xD1 - 0xA0,0xF2,0x85,0xD7,0xEA,0xB8,0xCF,0x9D - 0x34,0x66,0x11,0x43,0x7E,0x2C,0x5B,0x09 - 0x88,0xDA,0xAD,0xFF,0xC2,0x90,0xE7,0xB5 - 0x1C,0x4E,0x39,0x6B,0x56,0x04,0x73,0x21 - 0xF0,0xA2,0xD5,0x87,0xBA,0xE8,0x9F,0xCD - 0x64,0x36,0x41,0x13,0x2E,0x7C,0x0B,0x59 - 0xD8,0x8A,0xFD,0xAF,0x92,0xC0,0xB7,0xE5 - 0x4C,0x1E,0x69,0x3B,0x06,0x54,0x23,0x71 - 0x40,0x12,0x65,0x37,0x0A,0x58,0x2F,0x7D - 0xD4,0x86,0xF1,0xA3,0x9E,0xCC,0xBB,0xE9 - 0x68,0x3A,0x4D,0x1F,0x22,0x70,0x07,0x55 - 0xFC,0xAE,0xD9,0x8B,0xB6,0xE4,0x93,0xC1 - 0x10,0x42,0x35,0x67,0x5A,0x08,0x7F,0x2D - 0x84,0xD6,0xA1,0xF3,0xCE,0x9C,0xEB,0xB9 - 0x38,0x6A,0x1D,0x4F,0x72,0x20,0x57,0x05 - 0xAC,0xFE,0x89,0xDB,0xE6,0xB4,0xC3,0x91 - 0xE0,0xB2,0xC5,0x97,0xAA,0xF8,0x8F,0xDD - 0x74,0x26,0x51,0x03,0x3E,0x6C,0x1B,0x49 - 0xC8,0x9A,0xED,0xBF,0x82,0xD0,0xA7,0xF5 - 0x5C,0x0E,0x79,0x2B,0x16,0x44,0x33,0x61 - 0xB0,0xE2,0x95,0xC7,0xFA,0xA8,0xDF,0x8D - 0x24,0x76,0x01,0x53,0x6E,0x3C,0x4B,0x19 - 0x98,0xCA,0xBD,0xEF,0xD2,0x80,0xF7,0xA5 - 0x0C,0x5E,0x29,0x7B,0x46,0x14,0x63,0x31 +extern const uint8_t Hamming24EncodeTable0[256]; +extern const uint8_t Hamming24EncodeTable1[256]; +extern const uint8_t Hamming24EncodeTable2[4]; +extern const uint8_t Hamming24ParityTable[3][256]; -*low byte table - -TL 0x00,0x88,0x02,0x8A,0x04,0x8C,0x06,0x8E - 0x08,0x80,0x0A,0x82,0x0C,0x84,0x0E,0x86 - 0x11,0x99,0x13,0x9B,0x15,0x9D,0x17,0x9F - 0x19,0x91,0x1B,0x93,0x1D,0x95,0x1F,0x97 - 0x22,0xAA,0x20,0xA8,0x26,0xAE,0x24,0xAC - 0x2A,0xA2,0x28,0xA0,0x2E,0xA6,0x2C,0xA4 - 0x33,0xBB,0x31,0xB9,0x37,0xBF,0x35,0xBD - 0x3B,0xB3,0x39,0xB1,0x3F,0xB7,0x3D,0xB5 - 0x44,0xCC,0x46,0xCE,0x40,0xC8,0x42,0xCA - 0x4C,0xC4,0x4E,0xC6,0x48,0xC0,0x4A,0xC2 - 0x55,0xDD,0x57,0xDF,0x51,0xD9,0x53,0xDB - 0x5D,0xD5,0x5F,0xD7,0x59,0xD1,0x5B,0xD3 - 0x66,0xEE,0x64,0xEC,0x62,0xEA,0x60,0xE8 - 0x6E,0xE6,0x6C,0xE4,0x6A,0xE2,0x68,0xE0 - 0x77,0xFF,0x75,0xFD,0x73,0xFB,0x71,0xF9 - 0x7F,0xF7,0x7D,0xF5,0x7B,0xF3,0x79,0xF1 - 0x89,0x01,0x8B,0x03,0x8D,0x05,0x8F,0x07 - 0x81,0x09,0x83,0x0B,0x85,0x0D,0x87,0x0F - 0x98,0x10,0x9A,0x12,0x9C,0x14,0x9E,0x16 - 0x90,0x18,0x92,0x1A,0x94,0x1C,0x96,0x1E - 0xAB,0x23,0xA9,0x21,0xAF,0x27,0xAD,0x25 - 0xA3,0x2B,0xA1,0x29,0xA7,0x2F,0xA5,0x2D - 0xBA,0x32,0xB8,0x30,0xBE,0x36,0xBC,0x34 - 0xB2,0x3A,0xB0,0x38,0xB6,0x3E,0xB4,0x3C - 0xCD,0x45,0xCF,0x47,0xC9,0x41,0xCB,0x43 - 0xC5,0x4D,0xC7,0x4F,0xC1,0x49,0xC3,0x4B - 0xDC,0x54,0xDE,0x56,0xD8,0x50,0xDA,0x52 - 0xD4,0x5C,0xD6,0x5E,0xD0,0x58,0xD2,0x5A - 0xEF,0x67,0xED,0x65,0xEB,0x63,0xE9,0x61 - 0xE7,0x6F,0xE5,0x6D,0xE3,0x6B,0xE1,0x69 - 0xFE,0x76,0xFC,0x74,0xFA,0x72,0xF8,0x70 - 0xF6,0x7E,0xF4,0x7C,0xF2,0x7A,0xF0,0x78 -*--------------------------------------------------------------------- -*/ #endif \ No newline at end of file diff --git a/ttxline.h b/ttxline.h index be9c609..f42b617 100644 --- a/ttxline.h +++ b/ttxline.h @@ -19,10 +19,10 @@ class TTXLine /** Default destructor */ virtual ~TTXLine(); - /** Set the teletext line contents - * \param val - New value to set - * \param validateLine - If true, it ensures the line is checked and modified if needed to be transmission ready. - */ + /** Set the teletext line contents + * \param val - New value to set + * \param validateLine - If true, it ensures the line is checked and modified if needed to be transmission ready. + */ void Setm_textline(std::string const& val, bool validateLine=true); /** Access m_textline @@ -49,23 +49,19 @@ class TTXLine */ char GetCharAt(int xLoc); - /** Adds line to a linked list - * This is used for enhanced packets which might require multiples of the same row - */ - void AppendLine(std::string const& line); - - TTXLine* GetNextLine(){return _nextLine;} + /** Adds line to a linked list + * This is used for enhanced packets which might require multiples of the same row + */ + void AppendLine(std::string const& line); - void Dump(); + TTXLine* GetNextLine(){return _nextLine;} protected: private: std::string validate(std::string const& test); std::string m_textline; - TTXLine* _nextLine; - // If SetLine or SetChar can set the changed flag. - + TTXLine* _nextLine; }; #endif // TTXLINE_H diff --git a/ttxpage.cpp b/ttxpage.cpp index 23263e1..84e554a 100644 --- a/ttxpage.cpp +++ b/ttxpage.cpp @@ -137,116 +137,144 @@ bool TTXPage::m_LoadTTI(std::string filename) found=true; switch (i) { - case 0 : // "DS" - Destination inserter name - // DS,inserter - std::getline(filein, m_destination); - break; - case 1 : // "SP" - Source page file name - // SP is the path + name of the file from where is was loaded. Used also for Save. - // SP,c:\Minited\inserter\ONAIR\P100.tti - - std::getline(filein, line); - break; - case 2 : // "DE" - Description - // DE,Read back page 20/11/07 - std::getline(filein, m_description); - break; - case 3 : // "CT" - Cycle time (seconds) - // CT,8,T - std::getline(filein, line, ','); - p->SetCycleTime(atoi(line.c_str())); - std::getline(filein, line); - m_cycletimetype=line[0]=='T'?'T':'C'; - // TODO: CT is not decoded correctly - break; - case 4 : // "PN" - Page Number mppss - // Where m=1..8 - // pp=00 to ff (hex) - // ss=00 to 99 (decimal) - // PN,10000 - std::getline(filein, line); - if (line.length()<3) // Must have at least three characters for a page number + case 0 : // "DS" - Destination inserter name + { + // DS,inserter + std::getline(filein, m_destination); break; - m=line[0]; - if (m<'1' || m>'8') // Magazine must be 1 to 8 + } + case 1 : // "SP" - Source page file name + { + // SP is the path + name of the file from where is was loaded. Used also for Save. + // SP,c:\Minited\inserter\ONAIR\P100.tti + + std::getline(filein, line); break; - pageNumber=std::strtol(line.c_str(), &ptr, 16); - if (line.length()<5 && pageNumber<=0x8ff) // Page number without subpage? Shouldn't happen but you never know. + } + case 2 : // "DE" - Description + { + // DE,Read back page 20/11/07 + std::getline(filein, m_description); + break; + } + case 3 : // "CT" - Cycle time (seconds) + { + // CT,8,T + std::getline(filein, line, ','); + p->SetCycleTime(atoi(line.c_str())); + std::getline(filein, line); + m_cycletimetype=line[0]=='T'?'T':'C'; + // TODO: CT is not decoded correctly + break; + } + case 4 : // "PN" - Page Number mppss { - pageNumber*=0x100; + // Where m=1..8 + // pp=00 to ff (hex) + // ss=00 to 99 (decimal) + // PN,10000 + std::getline(filein, line); + if (line.length()<3) // Must have at least three characters for a page number + break; + m=line[0]; + if (m<'1' || m>'8') // Magazine must be 1 to 8 + break; + pageNumber=std::strtol(line.c_str(), &ptr, 16); + if (line.length()<5 && pageNumber<=0x8ff) // Page number without subpage? Shouldn't happen but you never know. + { + pageNumber*=0x100; + } + else // Normally has subpage digits + { + subpage=line.substr(3,2); + pageNumber=(pageNumber & 0xfff00) + std::strtol(subpage.c_str(),nullptr,10); + } + if (p->m_PageNumber!=FIRSTPAGE) // // Subsequent pages need new page instances + { + int pagestatus = p->GetPageStatus(); + TTXPage* newSubPage=new TTXPage(); // Create a new instance for the subpage + p->Setm_SubPage(newSubPage); // Put in a link to it + p=newSubPage; // And jump to the next subpage ready to populate + p->SetPageStatus(pagestatus); // inherit status of previous page instead of default + p->SetCycleTimeMode(m_cycletimetype); // inherit cycle time + p->SetCycleTime(m_cycletimeseconds); + } + p->SetPageNumber(pageNumber); + + break; } - else // Normally has subpage digits + case 5 : // "SC" - Subcode { - subpage=line.substr(3,2); - pageNumber=(pageNumber & 0xfff00) + std::strtol(subpage.c_str(),nullptr,10); + // SC,0000 + std::getline(filein, line); + subcode=std::strtol(line.c_str(), &ptr, 16); + + p->SetSubCode(subcode); + break; } - if (p->m_PageNumber!=FIRSTPAGE) // // Subsequent pages need new page instances + case 6 : // "PS" - Page status flags { - int pagestatus = p->GetPageStatus(); - TTXPage* newSubPage=new TTXPage(); // Create a new instance for the subpage - p->Setm_SubPage(newSubPage); // Put in a link to it - p=newSubPage; // And jump to the next subpage ready to populate - p->SetPageStatus(pagestatus); // inherit status of previous page instead of default - p->SetCycleTimeMode(m_cycletimetype); // inherit cycle time - p->SetCycleTime(m_cycletimeseconds); + // PS,8000 + std::getline(filein, line); + p->SetPageStatus(std::strtol(line.c_str(), &ptr, 16)); + break; } - p->SetPageNumber(pageNumber); - - break; - case 5 : // "SC" - Subcode - // SC,0000 - std::getline(filein, line); - subcode=std::strtol(line.c_str(), &ptr, 16); - - p->SetSubCode(subcode); - break; - case 6 : // "PS" - Page status flags - // PS,8000 - std::getline(filein, line); - p->SetPageStatus(std::strtol(line.c_str(), &ptr, 16)); - break; - case 7 : // "MS" - Mask - // MS,0 - std::getline(filein, line); // Mask is intended for TED to protecting regions from editing. - break; - case 8 : // "OL" - Output line - std::getline(filein, line, ','); - lineNumber=atoi(line.c_str()); - std::getline(filein, line); - if (lineNumber>MAXROW) break; - p->SetRow(lineNumber,line); - lines++; - break; - case 9 : // "FL"; - Fastext links - // FL,104,104,105,106,F,100 - for (int fli=0;fli<6;fli++) + case 7 : // "MS" - Mask { - if (fli<5) - std::getline(filein, line, ','); + // MS,0 + std::getline(filein, line); // Mask is intended for TED to protecting regions from editing. + break; + } + case 8 : // "OL" - Output line + { + std::getline(filein, line, ','); + lineNumber=atoi(line.c_str()); + std::getline(filein, line); + if (lineNumber>MAXROW) break; + p->SetRow(lineNumber,line); + lines++; + break; + } + case 9 : // "FL"; - Fastext links + { + // FL,104,104,105,106,F,100 + for (int fli=0;fli<6;fli++) + { + if (fli<5) + std::getline(filein, line, ','); + else + std::getline(filein, line); // Last parameter no comma + p->SetFastextLink(fli,std::strtol(line.c_str(), &ptr, 16)); + } + break; + } + case 10 : // "RD"; - not sure! + { + std::getline(filein, line); + break; + } + case 11 : // "RE"; - Set page region code 0..f + { + std::getline(filein, line); + p->SetRegion(std::strtol(line.c_str(), &ptr, 16)); + break; + } + case 12 : // "PF"; - not in the tti spec, page function and coding + { + std::getline(filein, line); + if (line.length()<3) + ss << "invalid page function/coding " << line << "\n"; else - std::getline(filein, line); // Last parameter no comma - p->SetFastextLink(fli,std::strtol(line.c_str(), &ptr, 16)); + { + SetPageFunctionInt(std::strtol(line.substr(0,1).c_str(), &ptr, 16)); + SetPageCodingInt(std::strtol(line.substr(2,1).c_str(), &ptr, 16)); + } + break; } - break; - case 10 : // "RD"; - not sure! - std::getline(filein, line); - break; - case 11 : // "RE"; - Set page region code 0..f - std::getline(filein, line); - p->SetRegion(std::strtol(line.c_str(), &ptr, 16)); - break; - case 12 : // "PF"; - not in the tti spec, page function and coding - std::getline(filein, line); - if (line.length()<3) - ss << "invalid page function/coding " << line << "\n"; - else + default: { - SetPageFunctionInt(std::strtol(line.substr(0,1).c_str(), &ptr, 16)); - SetPageCodingInt(std::strtol(line.substr(2,1).c_str(), &ptr, 16)); + ss << "Command not understood " << line << "\n"; } - break; - default: - ss << "Command not understood " << line << "\n"; } // switch } // if matched command // If the command was not found then skip the rest of the line @@ -328,9 +356,11 @@ void TTXPage::SetRow(unsigned int rownumber, std::string line) // assert(rownumber<=MAXROW); if (rownumber>MAXROW) return; - if (rownumber == 28 && line.length() >= 40){ + if (rownumber == 28 && line.length() >= 40) + { dc = line.at(0) & 0x0F; - if (dc == 0 || dc == 2 || dc == 3 || dc == 4){ + if (dc == 0 || dc == 2 || dc == 3 || dc == 4) + { // packet is X/28/0, X/28/2, X/28/3, or X/28/4 int triplet = line.at(1) & 0x3F; triplet |= (line.at(2) & 0x3F) << 6; @@ -381,7 +411,8 @@ int TTXPage::GetPageCount() // Annex A.1 states that pages with no sub-pages should be coded Mxx-0000. This is the default when no subcode is specified in tti file. // Annex E.2 states that the subcode may be used to transmit a BCD time code, e.g for an alarm clock. Where a non zero subcode is specified in the tti file keep it. - if (Special()){ + if (Special()) + { // "Special" pages (e.g. MOT, POP, GPOP, DRCS, GDRCS, MIP) should be coded sequentially in hexadecimal 0000-000F this->SetSubCode(0); } @@ -394,7 +425,8 @@ int TTXPage::GetPageCount() for (int i=0;i<4;i++) code[i]=0; for (TTXPage* p=this;p!=nullptr;p=p->m_SubPage) { - if (Special()){ + if (Special()) + { // "Special" pages (e.g. MOT, POP, GPOP, DRCS, GDRCS, MIP) should be coded sequentially in hexadecimal 0000-000F subcode = count; } @@ -505,75 +537,98 @@ void TTXPage::SetFastextLink(int link, int value) */ void TTXPage::Copy(TTXPage* src) { - // Deep copy the rows. - for (int i=0;i<=MAXROW;i++) - { - // Make sure that we have line object and that it does not get destroyed - - if (this->m_pLine[i]==nullptr) + // Deep copy the rows. + for (int i=0;i<=MAXROW;i++) { - this->m_pLine[i]=new TTXLine(); - } + // Make sure that we have line object and that it does not get destroyed - // If null then blank the line - if (src->m_pLine[i]==nullptr) - { - this->SetRow(i," "); // Just blank lines rather than destroy them - } - else - { - *(this->m_pLine[i])=*(src->m_pLine[i]); - } + if (this->m_pLine[i]==nullptr) + { + this->m_pLine[i]=new TTXLine(); + } - } - this->m_SubPage=nullptr; // (Might want to copy carousels but this is only used for subtitles so far) - // Copy everything else - this->CopyMetaData(src); + // If null then blank the line + if (src->m_pLine[i]==nullptr) + { + this->SetRow(i," "); // Just blank lines rather than destroy them + } + else + { + *(this->m_pLine[i])=*(src->m_pLine[i]); + } + } + this->m_SubPage=nullptr; // (Might want to copy carousels but this is only used for subtitles so far) + // Copy everything else + this->CopyMetaData(src); } void TTXPage::SetPageFunctionInt(int pageFunction) { - switch (pageFunction){ + switch (pageFunction) + { default: // treat page functions we don't know as level one pages case 0: + { m_pagefunction = LOP; break; + } case 2: + { m_pagefunction = GPOP; break; + } case 3: + { m_pagefunction = POP; break; + } case 4: + { m_pagefunction = GDRCS; break; + } case 5: + { m_pagefunction = DRCS; break; + } case 6: + { m_pagefunction = MOT; break; + } case 7: + { m_pagefunction = MIP; break; + } case 8: + { m_pagefunction = BTT; break; + } case 9: + { m_pagefunction = AIT; break; + } case 10: + { m_pagefunction = MPT; break; + } case 11: + { m_pagefunction = MPT_EX; break; + } } } PageCoding TTXPage::ReturnPageCoding(int pageCoding) { - switch (pageCoding){ + switch (pageCoding) + { default: // treat codings we don't know yet as normal text. case 0: return CODING_7BIT_TEXT; diff --git a/ttxpage.h b/ttxpage.h index 8a9b9f5..540a78b 100644 --- a/ttxpage.h +++ b/ttxpage.h @@ -14,7 +14,6 @@ #include #include "ttxline.h" -#include "hamm-tables.h" #define FIRSTPAGE 0x1ff00 @@ -179,8 +178,6 @@ class TTXPage inline bool PageChanged(){return pageChanged;}; static bool pageChanged; // / True if we have done some edits - void DebugDump() const; - inline bool Loaded() const {return m_Loaded;}; unsigned int GetLastPacket() {return m_lastpacket;}; diff --git a/ttxpagestream.cpp b/ttxpagestream.cpp index 78d1ade..9ff8250 100644 --- a/ttxpagestream.cpp +++ b/ttxpagestream.cpp @@ -38,22 +38,22 @@ TTXPageStream::~TTXPageStream() TTXLine* TTXPageStream::GetTxRow(uint8_t row) { - // Return a line OR NULL if the row does not exist - TTXLine* line=NULL; - if (IsCarousel()) - { - line=_CarouselPage->GetRow(row); - } - else // single page - { - line=GetRow(row); // _lineCounter is implied - } - if (line!=NULL) // Found a line - { - return line; - } - // No more lines? return NULL. - return NULL; + // Return a line OR NULL if the row does not exist + TTXLine* line=NULL; + if (IsCarousel()) + { + line=_CarouselPage->GetRow(row); + } + else // single page + { + line=GetRow(row); // _lineCounter is implied + } + if (line!=NULL) // Found a line + { + return line; + } + // No more lines? return NULL. + return NULL; } void TTXPageStream::StepNextSubpageNoLoop() @@ -66,28 +66,29 @@ void TTXPageStream::StepNextSubpageNoLoop() void TTXPageStream::StepNextSubpage() { - StepNextSubpageNoLoop(); - if (_CarouselPage==NULL) // Last carousel subpage? Loop to beginning - _CarouselPage=this; + StepNextSubpageNoLoop(); + if (_CarouselPage==NULL) // Last carousel subpage? Loop to beginning + _CarouselPage=this; } bool TTXPageStream::LoadPage(std::string filename) { - bool Loaded=false; + bool Loaded=false; //m_Init(); // Careful! We should move inits to the initialisation list and call the default constructor - m_PageNumber=FIRSTPAGE; // Force to replace the root page rather than add to the carousel - if (m_LoadTTI(filename)) - Loaded=true; - return Loaded; + m_PageNumber=FIRSTPAGE; // Force to replace the root page rather than add to the carousel + if (m_LoadTTI(filename)) + Loaded=true; + return Loaded; } bool TTXPageStream::operator==(const TTXPageStream& rhs) const { - if (this->GetSourcePage()==rhs.GetSourcePage()) - return true; - return false; + if (this->GetSourcePage()==rhs.GetSourcePage()) + return true; + return false; } -void TTXPageStream::IncrementUpdateCount(){ +void TTXPageStream::IncrementUpdateCount() +{ _updateCount = (_updateCount + 1) % 8; } diff --git a/ttxpagestream.h b/ttxpagestream.h index 5bf626f..41a7c77 100644 --- a/ttxpagestream.h +++ b/ttxpagestream.h @@ -12,142 +12,130 @@ */ class TTXPageStream : public TTXPage { - public: - /** Used to mark pages for deleting - * Pages are set to NOTFOUND at the start of each pass - * As pages are matched with files on drive they are set to FOUND - * At the end of a pass the file status is set to MARKED. The Service thread can now delete the page object. - */ - enum Status - { - NEW, // Just created - NOTFOUND, // Not found yet - FOUND, // Matched on drive - MARKED, // To be deleted - GONE // Safe to delete - }; - - /** Default constructor. Don't call this */ - TTXPageStream(); - /** Default destructor */ - virtual ~TTXPageStream(); - - /** The normal constructor - */ - TTXPageStream(std::string filename); - - bool GetCarouselFlag() { return _isCarousel; } - void SetCarouselFlag(bool val) { _isCarousel = val; } - - bool GetSpecialFlag() { return _isSpecial; } - void SetSpecialFlag(bool val) { _isSpecial = val; } - - bool GetNormalFlag() { return _isNormal; } - void SetNormalFlag(bool val) { _isNormal = val; } - - bool GetUpdatedFlag() { return _isUpdated; } - void SetUpdatedFlag(bool val) { _isUpdated = val; } - - int GetUpdateCount() {return _updateCount;} - void IncrementUpdateCount(); - - ///** Access _CurrentPage - //* \return The current value of _CurrentPage - //*/ - //TTXPageStream* GetCurrentPage(unsigned int line) { _CurrentPage->SetLineCounter(line);return _CurrentPage; } - - ///** Set _CurrentPage - //* \param val New value to set - //*/ - //void SetCurrentPage(TTXPageStream* val) { _CurrentPage = val; } - - - /** Is the page a carousel? - * Don't confuse this with the _isCarousel flag which is used to mark when a page changes between single/carousel - * \return True if there are subpages - */ - inline bool IsCarousel(){return Getm_SubPage()!=NULL;}; - - /** Set the time when this carousel expires - * ...which is the current time plus the cycle time - */ - inline void SetTransitionTime(int cycleTime){_transitionTime=time(nullptr) + cycleTime;}; - - /** Used to time carousels - * @return true if it is time to change carousel page - */ - inline bool Expired(){return _transitionTime<=time(nullptr);}; - - /** Step to the next page in a carousel - * Updates _CarouselPage; - */ - void StepNextSubpage(); - - // step to next subpage but don't loop back to the start - void StepNextSubpageNoLoop(); - - /** This is used by mag */ - TTXPage* GetCarouselPage(){return _CarouselPage;}; - - /** Get the row from the page. - * Carousels and main sequence pages are managed differently - */ - TTXLine* GetTxRow(uint8_t row); - - // The time that the file was modified. - time_t GetModifiedTime(){return _modifiedTime;}; - void SetModifiedTime(time_t timeVal){_modifiedTime=timeVal;}; - - bool LoadPage(std::string filename); - - /** - * @brief Set the flag used to detect file updates - * All files that are not MARKED are set NOT FOUND the start of a pass - * As files are matched with those on the drive are marked as FOUND - * At the end of the pass, any pages that are NOT FOUND are MARKED for delete - */ - void SetState(Status state){_fileStatus=state;}; - /** - * @return Flag used to monitor file status - */ - Status GetStatusFlag(){return _fileStatus;}; - - /** Used to enable list->remove - */ - bool operator==(const TTXPageStream& rhs) const; - - // Todo: These are migrating to TTXPage - void SetSelected(bool value){_Selected=value;}; /// Set the selected state to value - bool Selected(){return _Selected;}; /// Return the selected state - - void SetPacket29Flag(bool value){_loadedPacket29=value;}; // Used by PageList::CheckForPacket29 - bool GetPacket29Flag(){return _loadedPacket29;}; // Used by PageList::DeleteOldPages - - protected: - - private: - // Carousel control - // TTXPageStream* _CurrentPage; //!< Member variable "_currentPage" points to the subpage being transmitted - - time_t _transitionTime; // Records when the next carousel transition is due - - TTXPage* _CarouselPage; /// Pointer to the current subpage of a carousel - - // Things that affect the display list - time_t _modifiedTime; /// Poll this in case the source file changes (Used to detect updates) - Status _fileStatus; /// Used to mark if we found the file. (Used to detect deletions) - - bool _loadedPacket29; // Packet 29 for magazine was loaded from this page. Should only be set on one page in each magazine. - - bool _Selected; /// Marked as selected by the inserter P command - - bool _isCarousel; - bool _isSpecial; - bool _isNormal; - bool _isUpdated; - - int _updateCount; // update counter for special pages. - + public: + /** Used to mark pages for deleting + * Pages are set to NOTFOUND at the start of each pass + * As pages are matched with files on drive they are set to FOUND + * At the end of a pass the file status is set to MARKED. The Service thread can now delete the page object. + */ + enum Status + { + NEW, // Just created + NOTFOUND, // Not found yet + FOUND, // Matched on drive + MARKED, // To be deleted + GONE // Safe to delete + }; + + /** Default constructor. Don't call this */ + TTXPageStream(); + /** Default destructor */ + virtual ~TTXPageStream(); + + /** The normal constructor + */ + TTXPageStream(std::string filename); + + bool GetCarouselFlag() { return _isCarousel; } + void SetCarouselFlag(bool val) { _isCarousel = val; } + + bool GetSpecialFlag() { return _isSpecial; } + void SetSpecialFlag(bool val) { _isSpecial = val; } + + bool GetNormalFlag() { return _isNormal; } + void SetNormalFlag(bool val) { _isNormal = val; } + + bool GetUpdatedFlag() { return _isUpdated; } + void SetUpdatedFlag(bool val) { _isUpdated = val; } + + int GetUpdateCount() {return _updateCount;} + void IncrementUpdateCount(); + + /** Is the page a carousel? + * Don't confuse this with the _isCarousel flag which is used to mark when a page changes between single/carousel + * \return True if there are subpages + */ + inline bool IsCarousel(){return Getm_SubPage()!=NULL;}; + + /** Set the time when this carousel expires + * ...which is the current time plus the cycle time + */ + inline void SetTransitionTime(int cycleTime){_transitionTime=time(nullptr) + cycleTime;}; + + /** Used to time carousels + * @return true if it is time to change carousel page + */ + inline bool Expired(){return _transitionTime<=time(nullptr);}; + + /** Step to the next page in a carousel + * Updates _CarouselPage; + */ + void StepNextSubpage(); + + // step to next subpage but don't loop back to the start + void StepNextSubpageNoLoop(); + + /** This is used by mag */ + TTXPage* GetCarouselPage(){return _CarouselPage;}; + + /** Get the row from the page. + * Carousels and main sequence pages are managed differently + */ + TTXLine* GetTxRow(uint8_t row); + + // The time that the file was modified. + time_t GetModifiedTime(){return _modifiedTime;}; + void SetModifiedTime(time_t timeVal){_modifiedTime=timeVal;}; + + bool LoadPage(std::string filename); + + /** + * @brief Set the flag used to detect file updates + * All files that are not MARKED are set NOT FOUND the start of a pass + * As files are matched with those on the drive are marked as FOUND + * At the end of the pass, any pages that are NOT FOUND are MARKED for delete + */ + void SetState(Status state){_fileStatus=state;}; + /** + * @return Flag used to monitor file status + */ + Status GetStatusFlag(){return _fileStatus;}; + + /** Used to enable list->remove + */ + bool operator==(const TTXPageStream& rhs) const; + + // Todo: These are migrating to TTXPage + void SetSelected(bool value){_Selected=value;}; /// Set the selected state to value + bool Selected(){return _Selected;}; /// Return the selected state + + void SetPacket29Flag(bool value){_loadedPacket29=value;}; // Used by PageList::CheckForPacket29 + bool GetPacket29Flag(){return _loadedPacket29;}; // Used by PageList::DeleteOldPages + + protected: + + private: + // Carousel control + // TTXPageStream* _CurrentPage; //!< Member variable "_currentPage" points to the subpage being transmitted + + time_t _transitionTime; // Records when the next carousel transition is due + + TTXPage* _CarouselPage; /// Pointer to the current subpage of a carousel + + // Things that affect the display list + time_t _modifiedTime; /// Poll this in case the source file changes (Used to detect updates) + Status _fileStatus; /// Used to mark if we found the file. (Used to detect deletions) + + bool _loadedPacket29; // Packet 29 for magazine was loaded from this page. Should only be set on one page in each magazine. + + bool _Selected; /// Marked as selected by the inserter P command + + bool _isCarousel; + bool _isSpecial; + bool _isNormal; + bool _isUpdated; + + int _updateCount; // update counter for special pages. }; #endif // _TTXPAGESTREAM_H_ diff --git a/vbit2.cpp b/vbit2.cpp index 8cc8342..926ac8e 100644 --- a/vbit2.cpp +++ b/vbit2.cpp @@ -40,37 +40,34 @@ using namespace ttx; /* Options * --dir - * Example (and default) - * --dir /home/pi/teletext * Sets the pages directory and the location of vbit.conf. */ int main(int argc, char** argv) { - #ifdef WIN32 - _setmode(_fileno(stdout), _O_BINARY); // set stdout to binary mode stdout to avoid pesky line ending conversion - #endif - // std::cout << "VBIT2 started" << std::endl; - /// @todo option of adding a non standard config path - Configure *configure=new Configure(argc, argv); - PageList *pageList=new PageList(configure); + #ifdef WIN32 + _setmode(_fileno(stdout), _O_BINARY); // set stdout to binary mode stdout to avoid pesky line ending conversion + #endif + /// @todo option of adding a non standard config path + Configure *configure=new Configure(argc, argv); + PageList *pageList=new PageList(configure); - Service* svc=new Service(configure, pageList); // Need to copy the subtitle packet source for Newfor + Service* svc=new Service(configure, pageList); // Need to copy the subtitle packet source for Newfor - std::thread monitorThread(&FileMonitor::run, FileMonitor(configure, pageList)); - std::thread serviceThread(&Service::run, svc); - - if (configure->GetCommandPortEnabled()) - { - // only start command thread if required - std::thread commandThread(&Command::run, Command(configure, svc->GetSubtitle(), pageList) ); - commandThread.join(); - } - - // The threads should never stop, but just in case... - monitorThread.join(); - serviceThread.join(); + std::thread monitorThread(&FileMonitor::run, FileMonitor(configure, pageList)); + std::thread serviceThread(&Service::run, svc); - return 0; + if (configure->GetCommandPortEnabled()) + { + // only start command thread if required + std::thread commandThread(&Command::run, Command(configure, svc->GetSubtitle(), pageList) ); + commandThread.join(); + } + + // The threads should never stop, but just in case... + monitorThread.join(); + serviceThread.join(); + + return 0; }