diff --git a/Makefile b/Makefile index de8048bd3..9522cf2e3 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ INCLUDE += -I./lib/libchdr/include INCLUDE += -I./lib/flac/include INCLUDE += -I./lib/flac/src/include INCLUDE += -I./lib/bluetooth +INCLUDE += -I./lib/serial_server/library PRJ = MiSTer C_SRC = $(wildcard *.c) \ @@ -35,6 +36,7 @@ C_SRC = $(wildcard *.c) \ lib/libco/arm.c CPP_SRC = $(wildcard *.cpp) \ + $(wildcard ./lib/serial_server/library/*.cpp) \ $(wildcard ./support/*/*.cpp) IMG = $(wildcard *.png) diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index b157e1741..e4e3c2f5a 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -71,6 +71,10 @@ + + + + @@ -99,6 +103,7 @@ + @@ -143,6 +148,10 @@ + + + + @@ -170,6 +179,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index 7046df0cf..87c7d130c 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -42,6 +42,12 @@ {9e138a0b-53c4-4ae8-a59b-6b7bf2dcc01b} + + {6dcec61d-6e11-4dd2-b86b-0e60c7b7815d} + + + {63e50b49-7ff8-4651-a8a9-0b17cef3d364} + @@ -232,6 +238,21 @@ Source Files + + Source Files\support + + + Source Files\serial_server + + + Source Files\serial_server + + + Source Files\serial_server + + + Source Files\serial_server + @@ -450,5 +471,20 @@ Header Files + + Header Files\support + + + Header Files\serial_server + + + Header Files\serial_server + + + Header Files\serial_server + + + Header Files\serial_server + \ No newline at end of file diff --git a/lib/serial_server/gpl-2.0.txt b/lib/serial_server/gpl-2.0.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/lib/serial_server/gpl-2.0.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/lib/serial_server/library/Checksum.cpp b/lib/serial_server/library/Checksum.cpp new file mode 100644 index 000000000..dc3b5fc92 --- /dev/null +++ b/lib/serial_server/library/Checksum.cpp @@ -0,0 +1,372 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: checksum.cpp - Checksum function and test routines + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +// +// This file implements Fletcher's Checksum. The serial code uses this checksum, as it is very quick +// to calculate in assembly and offers reasonable error detection. +// For more information, see http://en.wikipedia.org/wiki/Fletcher%27s_checksum. +// +// Since it is faster in 8088 assembly code to deal with 16-bit quantities than 8-bit quantities, +// Fletcher's Checksum has been modified to calculate the 32-bit checksum, and then "fold" the result into a +// 16-bit quantity. Fletcher's 32-bit Checksum consists of two parts: concatenated 16-bit accumulators. +// To "fold" to 16-bits, The upper and lower 8-bits of each of these accumulators is XOR'd independently, and then +// the two results concatenated together, resulting in 16-bits. Although simpler, an early attempt to XOR the +// 16-bit accumulators results in poorer error detection behavior. Folding as described here results in error +// detection on par with Fletcher's 16-bit Checksum. +// +// With #define CHECKSUM_TEST, this file becomes a self-contained command line program that runs +// some statistical tests comparing various checksum algorithms with random 512-byte sectors and various +// levels of errors introduced. +// + +#include "Library.h" + +unsigned short checksum( unsigned short *wbuff, int wlen ) +{ + unsigned long a = 0xffff; + unsigned long b = 0xffff; + int t; + + for( t = 0; t < wlen; t++ ) + { + a += wbuff[t]; + b += a; + } + + a = (a & 0xffff) + (a >> 16); + b = (b & 0xffff) + (b >> 16); + a = (a & 0xffff) + (a >> 16); + b = (b & 0xffff) + (b >> 16); + +// Although tempting to use, for its simplicity and size/speed in assembly, the following folding +// algorithm results in many undetected single bit errors and therefore should not be used. +// return( (unsigned short) (a ^ b) ); + + return( (unsigned short) (((a & 0xff) << 8) ^ (a & 0xff00)) + (((b & 0xff00) >> 8) ^ (b & 0xff)) ); +} + +#ifdef CHECKSUM_TEST + +//==================================================================================================== +// +// Test Code +// + +#include +#include +#include +#include + +#define BUCKETS 65536 +#define BITTEST 16 + +unsigned char bit[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +class algorithm +{ +public: + virtual unsigned short checksum( unsigned char *data, int len ) = 0; + char *title; + unsigned long *found; + unsigned long zero; + unsigned long total; + unsigned long empty; + unsigned long min; + unsigned long max; + double stdev; + unsigned long bittest[ BITTEST ]; + unsigned long missed[ BITTEST ]; + algorithm *next; + algorithm( algorithm *last, char *new_title ); +}; + +algorithm::algorithm( algorithm *last, char *new_title ) +{ + zero = total = empty = min = max = 0; + stdev = 0.0; + for( int t = 0; t < BITTEST; t++ ) + { + bittest[t] = missed[t] = 0; + } + title = new_title; + next = last; +} + +//---------------------------------------------------------------------------------------------------- +// +// Standard CRC-16 +// +// http://sanity-free.org/134/standard_crc_16_in_csharp.html +// + +static unsigned short crc16_table[256]; + +class crc16_algorithm : public algorithm +{ +public: + crc16_algorithm( algorithm *last ) : algorithm( last, (char *) "crc-16" ) + { + unsigned short value; + unsigned short temp; + unsigned short i; + unsigned short j; + + for(i = 0; i < 256; ++i) + { + value = 0; + temp = i; + for(j = 0; j < 8; ++j) { + if(((value ^ temp) & 0x0001) != 0) { + value = (unsigned short)((value >> 1) ^ this->crc16_polynomial); + }else { + value >>= 1; + } + temp >>= 1; + } + crc16_table[i] = value; + } + } + + unsigned short checksum( unsigned char *data, int len ); + +private: + static const unsigned short crc16_polynomial = 0xA001; +}; + +unsigned short crc16_algorithm::checksum( unsigned char *data, int len ) +{ + unsigned short crc = 0; + int i; + + for(i = 0; i < len; ++i) + { + unsigned char index = (unsigned char)(crc ^ data[i]); + crc = (unsigned short)((crc >> 8) ^ crc16_table[index]); + } + + return( crc ); +} + +//---------------------------------------------------------------------------------------------------- +// +// Basic checksum (just add up the bytes) +// + +class basic_algorithm : public algorithm +{ +public: + unsigned short checksum( unsigned char *data, int len ); + basic_algorithm( algorithm *last ) : algorithm( last, (char *) "basic" ) { }; +}; + +unsigned short basic_algorithm::checksum( unsigned char *bbuff, int blen ) +{ + unsigned short sum = 0; + int i; + for( i = 0; i < blen; i++ ) + { + sum += bbuff[ i ]; + } + return( sum ); +} + +class fletcher16_algorithm : public algorithm +{ +public: + unsigned short checksum( unsigned char *data, int len ); + fletcher16_algorithm( algorithm *last ) : algorithm( last, (char *) "f-16" ) { } +}; + +unsigned short fletcher16_algorithm::checksum( unsigned char* data, int count ) +{ + unsigned short sum1 = 0; + unsigned short sum2 = 0; + int index; + + for( index = 0; index < count; ++index ) + { + sum1 = (sum1 + data[index]) % 255; + sum2 = (sum2 + sum1) % 255; + } + + return (sum2 << 8) | sum1; +} + +//---------------------------------------------------------------------------------------------------- +// +// Folded Fletcher's Checksum (what we use in the serial code, from the top of this file) +// + +class folded_fletcher32_algorithm : public algorithm +{ +public: + unsigned short checksum( unsigned char *data, int len ); + folded_fletcher32_algorithm( algorithm *last ) : algorithm( last, (char *) "fold-f-32" ) { } +}; + +unsigned short folded_fletcher32_algorithm::checksum( unsigned char* data, int count ) +{ + return( ::checksum( (unsigned short *) data, count/2 ) ); +} + +//---------------------------------------------------------------------------------------------------- +// +// Test Driver and Support routines +// + +void randomize_buff( unsigned char *bbuff, int blen ) +{ + int i; + for( i = 0; i < blen; i++ ) + bbuff[i] = rand() % 255; +} + +#define BBUFF_LENGTH 512 + +unsigned char bbuff[ BBUFF_LENGTH ]; + +int main( int argc, char *argv[] ) +{ + algorithm *a, *algorithms; + + unsigned short c; + + double p; + double average; + + unsigned long iterations; + + time_t now; + + algorithms = new folded_fletcher32_algorithm( NULL ); + algorithms = new fletcher16_algorithm( algorithms ); + algorithms = new crc16_algorithm( algorithms ); + algorithms = new basic_algorithm( algorithms ); + + time( &now ); + srand((unsigned int)now); + + if( argc != 2 ) + { + fprintf( stderr, "usage: checksum number_of_iterations\n" ); + exit( 1 ); + } + else + iterations = atol( argv[1] ); + +#define PRINTROW( E, F, G ) { printf( E ); for( a = algorithms; a; a = a->next ) printf( F, G ); printf( "\n" ); } + + printf( "\nnumber of iterations: %d\n\n", iterations ); + PRINTROW( " ", "%10s ", a->title ); + PRINTROW( "=======", "============", NULL ); + + for( a = algorithms; a; a = a->next ) + { + a->found = (unsigned long *) calloc( BUCKETS, sizeof(long) ); + + a->zero = (unsigned long) a->checksum( bbuff, BBUFF_LENGTH ); + + a->min = iterations+1; + } + + printf( "\n" ); + PRINTROW( "zero ", "%10d ", a->zero ); + + for( int t = 0; t < iterations; t++ ) + { + randomize_buff( bbuff, BBUFF_LENGTH ); + + for( a = algorithms; a; a = a->next ) + a->found[ a->checksum( bbuff, BBUFF_LENGTH ) ]++; + } + + average = iterations / 65536.0; + + for( int t = 0; t < 65536; t++ ) + { + for( a = algorithms; a; a = a->next ) + { + a->total += a->found[ t ]; + if( !a->found[ t ] ) + a->empty++; + if( a->found[ t ] > a->max ) + a->max = a->found[ t ]; + if( a->found[ t ] < a->min ) + a->min = a->found[ t ]; + p = a->found[ t ] - average; + a->stdev += p*p; + } + } + + p = 1.0 / (65536.0-1.0); + for( a = algorithms; a; a = a->next ) + { + a->stdev = sqrt( p * a->stdev ); + if( a->total != iterations ) + fprintf( stderr, "Bad %s\n", a->title ); + } + + printf( "\nchecksum distribution test:\n" ); + PRINTROW( "empty ", "%10d ", a->empty ); + PRINTROW( "min ", "%10d ", a->min ); + PRINTROW( "max ", "%10d ", a->max ); + PRINTROW( "stdev ", "%10.4lf ", a->stdev ); + + for( int t = 0; t < iterations; t++ ) + { + randomize_buff( bbuff, BBUFF_LENGTH ); + + for( int b = 0; b < BITTEST; b++ ) + { + for( a = algorithms; a; a = a->next ) + { + a->bittest[ b ] = (a->checksum)( bbuff, BBUFF_LENGTH ); + } + + bbuff[ rand() % 512 ] ^= bit[ rand() % 8 ]; + + if( b > 0 ) + { + for( a = algorithms; a; a = a->next ) + { + if( a->bittest[ 0 ] == a->bittest[ b ] ) + a->missed[ b ]++; + } + } + } + } + + printf( "\nbit change test:\n" ); + for( int t = 1; t < BITTEST; t++ ) + { + printf( "%2d ", t ); + for( a = algorithms; a; a = a->next ) + printf( "%7d ", a->missed[ t ] ); + printf( "\n" ); + } +} + +#endif + + + + diff --git a/lib/serial_server/library/FlatImage.h b/lib/serial_server/library/FlatImage.h new file mode 100644 index 000000000..843441fed --- /dev/null +++ b/lib/serial_server/library/FlatImage.h @@ -0,0 +1,97 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: FlatImage.h - Header file for basic flat disk image support +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include "Library.h" +#include + +class FlatImage : public Image +{ +private: + class FileAccess fp; + +public: + FlatImage( char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS ) : Image( name, p_readOnly, p_drive, p_create, p_cyl, p_head, p_sect, p_useCHS ) + { + long filesize; + + if( p_create ) + { + char buff[512]; + unsigned long size; + double sizef; + FileAccess cf; + char sizeChar; + + size = (unsigned long) p_cyl * (unsigned long) p_sect * (unsigned long) p_head; + if( size > cf.MaxSectors ) + log( -1, "'%s', can't create flat file with size greater than %lu 512-byte sectors", name, cf.MaxSectors ); + sizef = size / 2048.0; // 512 byte sectors -> MB + sizeChar = 'M'; + if( sizef < 1 ) + { + sizef *= 1024; + sizeChar = 'K'; + } + + if( cf.Create( name ) ) + { + memset( &buff[0], 0, 512 ); + while( size-- ) + cf.Write( &buff[0], 512 ); + + if( p_cyl > 1024 ) + log( 0, "Created file '%s', size %.2lf %cB", name, sizef, sizeChar ); + else + log( 0, "Created file '%s', geometry %u:%u:%u, size %.2lf %cB", name, p_cyl, p_head, p_sect, sizef, sizeChar ); + cf.Close(); + } + } + + fp.Open( name ); + + totallba = fp.SizeSectors(); + + init( name, p_readOnly, p_drive, p_cyl, p_head, p_sect, p_useCHS ); + } + + ~FlatImage() + { + fp.Close(); + } + + void seekSector( unsigned long lba ) + { + fp.SeekSectors( lba ); + } + + void writeSector( void *buff ) + { + fp.Write( buff, 512 ); + } + + void readSector( void *buff ) + { + fp.Read( buff, 512 ); + } +}; + diff --git a/lib/serial_server/library/Image.cpp b/lib/serial_server/library/Image.cpp new file mode 100644 index 000000000..288143cf6 --- /dev/null +++ b/lib/serial_server/library/Image.cpp @@ -0,0 +1,330 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: image.cpp - Abstract base class for disk image support +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include "Library.h" +#include +#include +#include +#include + +struct floppyInfo floppyInfos[] = +{ + { 1, 2949120 / 512, 6, 80, 2, 36 }, // 2.88MB 3.5" + { 0, 2867200 / 512, 6, 80, 2, 36 }, // 2.88MB 3.5" (alternate spelling with 2.8) + { 0, 2969600 / 512, 6, 80, 2, 36 }, // 2.88MB 3.5" (alternate spelling with 2.9) + { 1, 1474560 / 512, 4, 80, 2, 18 }, // 1.44MB 3.5" + { 0, 1433600 / 512, 4, 80, 2, 18 }, // 1.44MB 3.5" (alternate spelling with 1.4) + { 1, 1228800 / 512, 2, 80, 2, 15 }, // 1.2MB 5.25" + { 1, 737280 / 512, 3, 80, 1, 18 }, // 720KB 3.5" + { 1, 368640 / 512, 1, 40, 2, 9 }, // 360KB 5.25" + { 1, 327680 / 512, 0, 40, 2, 8 }, // 320KB 5.25" + { 1, 184320 / 512, 0, 40, 1, 9 }, // 180KB 5.25" single sided + { 1, 163840 / 512, 0, 40, 1, 8 }, // 160KB 5.25" single sided + { 0, 0, 0, 0, 0, 0 } +}; + +struct floppyInfo *FindFloppyInfoBySize( double size ) +{ + struct floppyInfo *fi; + + for( fi = floppyInfos; fi->size != 0 && !(size+5 > fi->size && size-5 < fi->size); fi++ ) ; + + if( fi->size == 0 ) + fi = NULL; + + return( fi ); +} + +void flipEndian( unsigned short *buff, unsigned int len ) +{ + for( unsigned int t = 0; t < len/2; t++ ) + buff[t] = (buff[t] & 0xff) << 8 | (buff[t] & 0xff00) >> 8; +} + +Image::Image( const char *name, int p_readOnly, int p_drive ) +{ +} + +Image::Image( const char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_lba ) +{ +} + +Image::Image( const char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS ) +{ +} + +void Image::init( const char *name, int p_readOnly, int p_drive, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS ) +{ + double sizef; + char sizeChar; + struct floppyInfo *f; + + for( const char *c = shortFileName = name; *c; c++ ) + if( *c == '\\' || *c == '/' || *c == ':' ) + shortFileName = c+1; + + if( *(shortFileName) == 0 ) + { + log( 1, "Can't parse '%s' for short file name\n\n", name ); + shortFileName = "SerDrive"; + } + + readOnly = p_readOnly; + drive = p_drive; + + if( totallba > 0xfffffff ) // lba28 limit - 28 bits + log( -1, "'%s', Image size larger than LBA28 maximum of 137,438,952,960 bytes, %lu", name, totallba ); + + if( totallba == 0 ) + log( -1, "'%s', Image size zero?" ); + + floppy = 0; + for( f = floppyInfos; f->size && !(f->size == totallba && f->real); f++ ) ; + if( f->size ) + { + floppy = 1; + floppyType = f->type; + p_useCHS = 1; + p_cyl = f->cylinders; + p_head = f->heads; + p_sect = f->sectors; + totallba = p_cyl * p_head * p_sect; + } + + if( p_cyl ) + { + if( (p_sect > 255 || p_sect < 1) || (p_head > 16 || p_head < 1) || (p_cyl > 65536 || p_cyl < 1) ) + log( -1, "'%s', parts of the CHS geometry (%lu:%lu:%lu) are out of the range (1-65536:1-16:1-255)", name, p_cyl, p_head, p_sect ); + else if( totallba != (p_sect * p_head * p_cyl) ) + log( -1, "'%s', file size does not match geometry", name ); + sect = p_sect; + head = p_head; + cyl = p_cyl; + } + else + { + if( totallba > 65536*16*63 ) + { + log( 0, "'%s': Warning: Image size is greater than derived standard CHS maximum, limiting CHS to 65535:16:63, consider using -g to specify geometry", name ); + cyl = 65536; + head = 16; + sect = 63; + } + else if( (totallba % 16) != 0 || ((totallba/16) % 63) != 0 ) + { + log( -1, "'%s', file size does not match standard CHS geometry (x:16:63), please specify geometry explicitly with -g", name ); + } + else + { + sect = 63; + head = 16; + cyl = (totallba / sect / head); + if( cyl > 65536 ) + { + log( -1, "'%s', derived standard CHS geometry of %lu:16:63 is has more cylinders than 65536, please specify geometry explicitly with -g", name, cyl, head, sect ); + } + } + } + + useCHS = p_useCHS; + + sizef = totallba/2048.0; + sizeChar = 'M'; + if( sizef < 1 ) + { + sizef *= 1024; + sizeChar = 'K'; + } + if( useCHS ) + log( 0, "%s: %s with CHS geometry %u:%u:%u, size %.2lf %cB", + name, (floppy ? "Floppy Disk" : "Hard Disk"), cyl, head, sect, sizef, sizeChar ); + else + log( 0, "%s: %s with %lu LBA sectors, size %.2lf %cB (CHS geometry %u:%u:%u)", + name, (floppy ? "Floppy Disk" : "Hard Disk"), totallba, sizef, sizeChar, cyl, head, sect ); +} + +int Image::parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_head, unsigned long *p_sect ) +{ + char *c, *s, *h; + unsigned long cyl, sect, head; + + c = str; + for( h = c; *h && *h != ':' && *h != 'x' && *h != 'X'; h++ ) ; + if( !*h ) + return( 0 ); + + *h = '\0'; + h++; + for( s = h+1; *s && *s != ':' && *s != 'x' && *s != 'X'; s++ ) ; + if( !*s ) + return( 0 ); + + *s = '\0'; + s++; + + cyl = atol(c); + head = atol(h); + sect = atol(s); + + if( cyl == 0 || sect == 0 || head == 0 ) + return( 0 ); + + *p_cyl = cyl; + *p_head = head; + *p_sect = sect; + + return( 1 ); +} + +#define ATA_wGenCfg 0 +#define ATA_wCylCnt 1 +#define ATA_wHeadCnt 3 +#define ATA_wBpTrck 4 +#define ATA_wBpSect 5 +#define ATA_wSPT 6 + +#define ATA_strSerial 10 +#define ATA_strSerial_Length 20 + +#define ATA_strFirmware 23 +#define ATA_strFirmware_Length 8 + +#define ATA_strModel 27 +#define ATA_strModel_Length 40 // Maximum allowable length of the string according to the ATA spec +#define XTIDEBIOS_strModel_Length 30 // Maximum length copied out of the ATA information by the BIOS + +#define ATA_wCaps 49 +#define ATA_wCurCyls 54 +#define ATA_wCurHeads 55 +#define ATA_wCurSPT 56 +#define ATA_dwCurSCnt 57 +#define ATA_dwLBACnt 60 + +// Words carved out of the vendor specific area for our use +// +#define ATA_wSerialServerVersion 157 +#define ATA_wSerialDriveFlags 158 +#define ATA_wSerialPortAndBaud 159 + +// Defines used in the words above +// +#define ATA_wCaps_LBA 0x200 + +#define ATA_wGenCfg_FIXED 0x40 + +// These are all shifted by 1 bit to the right, so that SerialDPT_Finalize can shift them into proper position +// and shift the high order bit into the carry flag to indicate a floppy drive is present. +// +#define ATA_wSerialDriveFlags_Floppy 0x88 +#define ATA_wSerialDriveFlags_Present 0x02 +#define ATA_wSerialDriveFlags_FloppyType_FieldPosition 4 + +struct comPorts { + unsigned long port; + unsigned char com; +}; +struct comPorts supportedComPorts[] = +{ + { 0x3f8, '1' }, + { 0x2f8, '2' }, + { 0x3e8, '3' }, + { 0x2e8, '4' }, + { 0x2f0, '5' }, + { 0x3e0, '6' }, + { 0x2e0, '7' }, + { 0x260, '8' }, + { 0x368, '9' }, + { 0x268, 'A' }, + { 0x360, 'B' }, + { 0x270, 'C' }, + { 0, 0 } +}; + +void Image::respondInquire( unsigned short *buff, unsigned short originalPortAndBaud, struct baudRate *baudRate, unsigned short port, unsigned char scan ) +{ + char formatBuff[ 128 ]; + char speedBuff[ 128 ]; + + memset( &buff[0], 0, 514 ); + + if( scan ) + { + unsigned short comPort = 0; + struct comPorts *cp; + + if( port ) + { + for( cp = supportedComPorts; cp->port && cp->port != port; cp++ ) ; + if( cp->port ) + comPort = cp->com; + } + + if( comPort ) + sprintf( speedBuff, " (COM%c/%s)", comPort, baudRate->display ); + else + sprintf( speedBuff, " (%s baud)", shortFileName, baudRate->display ); + + sprintf( formatBuff, "%.*s%s ", XTIDEBIOS_strModel_Length - strlen(speedBuff), shortFileName, speedBuff ); + } + else + sprintf( formatBuff, "%.*s ", XTIDEBIOS_strModel_Length, shortFileName ); + strncpy( (char *) &buff[ATA_strModel], formatBuff, ATA_strModel_Length ); + flipEndian( &buff[ATA_strModel], ATA_strModel_Length ); + + strncpy( (char *) &buff[ATA_strSerial], "SerialDrive ", ATA_strSerial_Length ); + flipEndian( &buff[ATA_strSerial], ATA_strSerial_Length ); + + sprintf( formatBuff, "%d.%d ", SERIAL_SERVER_MAJORVERSION, SERIAL_SERVER_MINORVERSION ); + strncpy( (char *) &buff[ATA_strFirmware], formatBuff, ATA_strFirmware_Length ); + flipEndian( &buff[ATA_strFirmware], ATA_strFirmware_Length ); + + buff[ ATA_wCylCnt ] = cyl; + buff[ ATA_wHeadCnt ] = head; + buff[ ATA_wSPT ] = sect; + + if( !useCHS ) + { + buff[ ATA_wCaps ] = ATA_wCaps_LBA; + buff[ ATA_dwLBACnt ] = (unsigned short) (totallba & 0xffff); + buff[ ATA_dwLBACnt+1 ] = (unsigned short) (totallba >> 16); + } + + // We echo back the port and baud that we were called on from the client, + // the client then uses this value to finalize the DPT. + // + buff[ ATA_wSerialPortAndBaud ] = originalPortAndBaud; + + // In case the client requires a specific server version... + // + buff[ ATA_wSerialServerVersion ] = (SERIAL_SERVER_MAJORVERSION << 8) | SERIAL_SERVER_MINORVERSION; + + buff[ ATA_wSerialDriveFlags ] = ATA_wSerialDriveFlags_Present; + if( floppy ) + buff[ ATA_wSerialDriveFlags ] |= + ATA_wSerialDriveFlags_Floppy | (floppyType << ATA_wSerialDriveFlags_FloppyType_FieldPosition); + + // we always set this, so that the bulk of the BIOS will consider this disk as a hard disk + // + buff[ ATA_wGenCfg ] = ATA_wGenCfg_FIXED; +} + diff --git a/lib/serial_server/library/Library.h b/lib/serial_server/library/Library.h new file mode 100644 index 000000000..05a4a55c8 --- /dev/null +++ b/lib/serial_server/library/Library.h @@ -0,0 +1,96 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: library.h - Include file for users of the library +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#ifndef LIBRARY_H_INCLUDED +#define LIBRARY_H_INCLUDED + +#define SERIAL_SERVER_MAJORVERSION 1 +#define SERIAL_SERVER_MINORVERSION 0 + +#include + +void log( int level, const char *message, ... ); + +unsigned long GetTime(void); +unsigned long GetTime_Timeout(void); + +unsigned short checksum( unsigned short *wbuff, int wlen ); + +struct floppyInfo { + unsigned char real; + unsigned long size; + unsigned char type; + unsigned char cylinders; + unsigned char heads; + unsigned char sectors; +}; + +struct floppyInfo *FindFloppyInfoBySize( double size ); + +class Image +{ +public: + virtual void seekSector( unsigned long lba ) = 0; + + virtual void writeSector( void *buff ) = 0; + + virtual void readSector( void *buff ) = 0; + + Image( const char *name, int p_readOnly, int p_drive ); + Image( const char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_lba ); + Image( const char *name, int p_readOnly, int p_drive, int p_create, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS ); + + virtual ~Image() {}; + + unsigned long cyl, sect, head; + unsigned char floppy, floppyType; + int useCHS; + + unsigned long totallba; + + const char *shortFileName; + int readOnly; + int drive; + + static int parseGeometry( char *str, unsigned long *p_cyl, unsigned long *p_head, unsigned long *p_sect ); + + void respondInquire( unsigned short *buff, unsigned short originalPortAndBaud, struct baudRate *baudRate, unsigned short port, unsigned char scan ); + + void init( const char *name, int p_readOnly, int p_drive, unsigned long p_cyl, unsigned long p_head, unsigned long p_sect, int p_useCHS ); +}; + +struct baudRate { + unsigned long rate; + unsigned char divisor; + const char *display; + speed_t speed; +}; +struct baudRate *baudRateMatchString( const char *str ); +struct baudRate *baudRateMatchDivisor( unsigned char divisor ); + +#include +#include + +void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel ); + +#endif diff --git a/lib/serial_server/library/LinuxFile.h b/lib/serial_server/library/LinuxFile.h new file mode 100644 index 000000000..6cd1a42d2 --- /dev/null +++ b/lib/serial_server/library/LinuxFile.h @@ -0,0 +1,140 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: Win32File.h - Microsoft Windows file system access. +// +// Routines for accessing the file system under Win32. It's important +// to use these direct Win32 calls for large files, since FILE * routines, +// in particular ftell() and fseek(), are limited to signed 32-bits (2 GB). +// These are also likely faster since they are more direct. +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include +#include +#include +#include +#include "../library/Library.h" + +class FileAccess +{ +public: + int Create( char *p_name ) + { + fp = open(p_name, O_CREAT | O_EXCL | O_RDWR, 0666); + + if( fp < 0 ) + { + if( errno == EEXIST ) + { + log( 0, "'%s', file already exists", p_name ); + return( 0 ); + } + else + log( -1, "'%s', could not create file", p_name ); + } + + name = p_name; + + return( 1 ); + } + + void Open( char *p_name ) + { + fp = open(p_name, O_RDWR); + + if( fp < 0 ) + log( -1, "'%s', could not open file", p_name ); + + name = p_name; + } + + void Close() + { + if( fp ) + { + if( close( fp ) ) + log( 0, "'%s', could not close file handle", name ? name : "unknown" ); + } + } + + unsigned long SizeSectors(void) + { + struct stat64 st; + unsigned long i; + + if( fstat64( fp, &st ) ) + log( -1, "'%s', could not retrieve file size (error %i)", name, errno ); + + if( st.st_size & 0x1ff ) + log( -1, "'%s', file size is not a multiple of 512 byte sectors", name ); + + if( (st.st_size >> 32) > 0x1f ) + log( -1, "'%s', file size greater than LBA28 limit of 137,438,952,960 bytes", name ); + + i = st.st_size >> 9; + + return( (unsigned long) i ); + } + + void SeekSectors( unsigned long lba ) + { + off64_t offset, result; + + offset = lba; + offset <<= 9; + + result = lseek64(fp, offset, SEEK_SET); + if( result < 0 || result != offset) + log( -1, "'%s', Failed to seek to lba=%lu", name, lba ); + } + + void Read( void *buff, unsigned long len ) + { + unsigned long out_len; + + out_len = read(fp, buff, len); + if( out_len < 0 || len != out_len ) + log( -1, "'%s', ReadFile failed", name ); + } + + void Write( void *buff, unsigned long len ) + { + unsigned long out_len; + + out_len = write(fp, buff, len); + if( out_len < 0 || len != out_len ) + log( -1, "'%s', WriteFile failed", name ); + } + + FileAccess() + { + fp = 0; + name = NULL; + } + + // LBA 28 limit - 28-bits (could be 1 more, but not worth pushing it) + const static unsigned long MaxSectors = 0xfffffff; +#define USAGE_MAXSECTORS "137438 MB (LBA28 limit)" + +private: + int fp; + char *name; +}; + diff --git a/lib/serial_server/library/LinuxSerial.h b/lib/serial_server/library/LinuxSerial.h new file mode 100644 index 000000000..164abd2d6 --- /dev/null +++ b/lib/serial_server/library/LinuxSerial.h @@ -0,0 +1,122 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: Win32Serial.h - Microsoft Windows serial code +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include +#include +#include +#include +#include +#include "../library/Library.h" + +#define PIPENAME "\\\\.\\pipe\\xtide" + +class SerialAccess +{ +public: + void Connect( const char *name, struct baudRate *p_baudRate ) + { + char buff1[20], buff2[1024]; + + baudRate = p_baudRate; + + pipe = -1; + + if( !access(name, R_OK | W_OK) ) + { + struct termios state; + + log( 0, "Opening %s (%s baud)", name, baudRate->display ); + + pipe = open(name, O_RDWR); + if( pipe < 0 ) + log( -1, "Could not Open \"%s\"", name ); + + tcgetattr(pipe, &state); + cfmakeraw(&state); + state.c_cflag |= CRTSCTS | CLOCAL; + state.c_lflag &= ~ECHO; + cfsetispeed(&state, baudRate->speed); + cfsetospeed(&state, baudRate->speed); + tcsetattr(pipe, TCSAFLUSH, &state); + } + else + log( -1, "Serial port '%s' not found", name ); + } + + void Disconnect() + { + if( pipe ) + { + close( pipe ); + pipe = -1; + } + } + + unsigned long readCharacters( void *buff, unsigned long len ) + { + unsigned long readLen; + int ret; + + readLen = read(pipe, buff, len); + + if( readLen < 0 ) + log( -1, "read serial failed (error code %i)", errno ); + + return( readLen ); + } + + int writeCharacters( void *buff, unsigned long len ) + { + unsigned long writeLen; + int ret; + + writeLen = write(pipe, buff, len); + + if( writeLen < 0 ) + log( -1, "write serial failed (error code %i)", errno ); + + return( 1 ); + } + + SerialAccess() + { + pipe = 0; + speedEmulation = 0; + resetConnection = 0; + baudRate = NULL; + } + + ~SerialAccess() + { + Disconnect(); + } + + int speedEmulation; + int resetConnection; + + struct baudRate *baudRate; + +private: + int pipe; +}; + diff --git a/lib/serial_server/library/Process.cpp b/lib/serial_server/library/Process.cpp new file mode 100644 index 000000000..caee9009b --- /dev/null +++ b/lib/serial_server/library/Process.cpp @@ -0,0 +1,404 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: process.cpp - Processes commands received over the serial port +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include "Library.h" +#include +#include +#include + +union _buff { + struct { + unsigned char command; + unsigned char driveAndHead; + unsigned char count; + unsigned char sector; + unsigned short cylinder; + } chs; + struct { + unsigned char command; + unsigned char bits24; + unsigned char count; + unsigned char bits00; + unsigned char bits08; + unsigned char bits16; + } lba; + struct { + unsigned char command; + unsigned char driveAndHead; + unsigned char count; + unsigned char scan; + unsigned char port; + unsigned char baud; + } inquire; + struct { + unsigned char command; + unsigned char driveAndHead; + unsigned char count; + unsigned char scan; + unsigned short PackedPortAndBaud; + } inquirePacked; + unsigned char b[514]; + unsigned short w[257]; +} buff; + +#define SERIAL_COMMAND_HEADER 0xa0 + +#define SERIAL_COMMAND_WRITE 1 +#define SERIAL_COMMAND_READWRITE 2 +#define SERIAL_COMMAND_RWMASK 3 +#define SERIAL_COMMAND_INQUIRE 0 + +#define SERIAL_COMMAND_MASK 0xe3 +#define SERIAL_COMMAND_HEADERMASK 0xe0 + +#define ATA_COMMAND_LBA 0x40 +#define ATA_COMMAND_HEADMASK 0xf + +#define ATA_DriveAndHead_Drive 0x10 + +void logBuff( const char *message, unsigned long buffoffset, unsigned long readto, int verboseLevel ) +{ + char logBuff[ 514*9 + 10 ]; + int logCount; + + if( verboseLevel == 5 || (verboseLevel >= 3 && buffoffset == readto) ) + { + if( verboseLevel == 3 && buffoffset > 11 ) + logCount = 11; + else + logCount = buffoffset; + + for( int t = 0; t < logCount; t++ ) + sprintf( &logBuff[t*9], "[%3d:%02x] ", t, buff.b[t] ); + if( logCount != buffoffset ) + sprintf( &logBuff[logCount*9], "... " ); + + log( 3, "%s%s", message, logBuff ); + } +} + +void processRequests( SerialAccess *serial, Image *image0, Image *image1, int timeoutEnabled, int verboseLevel ) +{ + unsigned char workCommand; + int workOffset, workCount; + + unsigned long mylba; + unsigned long readto; + unsigned long buffoffset; + unsigned long lasttick; + unsigned short crc; + unsigned long GetTime_Timeout_Local; + unsigned long len; + Image *img; + unsigned long cyl, sect, head; + unsigned long perfTimer; + unsigned char lastScan; + + GetTime_Timeout_Local = GetTime_Timeout(); + + buffoffset = 0; + readto = 0; + workCount = workOffset = workCommand = 0; + lastScan = 0; + + // + // Floppy disks must come after any hard disks + // + if( (image0 && image0->floppy) && (image1 && !image1->floppy) ) + { + img = image0; + image0 = image1; + image1 = img; + } + + lasttick = GetTime(); + + while( (len = serial->readCharacters( &buff.b[buffoffset], (readto ? readto-buffoffset : 1) )) ) + { + buffoffset += len; + + // + // For debugging, look at the incoming packet + // + if( verboseLevel >= 3 ) + logBuff( " Received: ", buffoffset, readto, verboseLevel ); + + if( timeoutEnabled && readto && GetTime() > lasttick + GetTime_Timeout_Local ) + { + log( 1, "Timeout waiting on data from client, aborting previous command" ); + + workCount = workOffset = workCommand = 0; + readto = 0; + + if( len <= 8 && (buff.b[buffoffset-len] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER ) + { + // assume that we are at the front of a new command + // + memcpy( &buff.b[0], &buff.b[buffoffset-len], len ); + buffoffset = len; + readto = 8; + // fall through to normal processing + } + else if( len == 1 ) + { + // one new character, treat it like any other new character received, discarding the buffer + // + buff.b[0] = buff.b[buffoffset-1]; + buffoffset = 1; + // fall through to normal processing + } + else + { + // discard even the newly received data and start listening anew + // + buffoffset = 0; + continue; + } + } + + lasttick = GetTime(); + + // + // No work currently to do, look at each character as they come in... + // + if( !readto ) + { + if( (buff.b[0] & SERIAL_COMMAND_HEADERMASK) == SERIAL_COMMAND_HEADER ) + { + // + // Found our command header byte to start a commnad sequence, read the next 7 and evaluate + // + readto = 8; + continue; + } + else + { + // + // Spurious characters, discard + // + if( verboseLevel >= 2 ) + { + if( buff.b[0] >= 0x20 && buff.b[0] <= 0x7e ) + log( 2, "Spurious: [%d:%c]", buff.b[0], buff.b[0] ); + else + log( 2, "Spurious: [%d]", buff.b[0] ); + } + buffoffset = 0; + continue; + } + } + + // + // Partial packet received, keep reading... + // + if( readto && buffoffset < readto ) + continue; + + // + // Read 512 bytes from serial port, only one command reads that many characters: Write Sector + // + if( buffoffset == readto && readto == 514 ) + { + buffoffset = readto = 0; + if( (crc = checksum( &buff.w[0], 256 )) != buff.w[256] ) + { + log( 0, "Bad Write Sector Checksum" ); + continue; + } + + if( img->readOnly ) + { + log( 1, "Attempt to write to read-only image" ); + continue; + } + + img->seekSector( mylba + workOffset ); + img->writeSector( &buff.w[0] ); + + // + // Echo back the CRC + // + if( !serial->writeCharacters( &buff.w[256], 2 ) ) + break; + + workOffset++; + workCount--; + + if( workCount ) + readto = 1; // looking for continuation ACK + } + + // + // 8 byte command received, or a continuation of the previous command + // + else if( (buffoffset == readto && readto == 8) || + (buffoffset == readto && readto == 1 && workCount) ) + { + buffoffset = readto = 0; + if( workCount ) + { + if( verboseLevel > 1 ) + log( 2, " Continuation: Offset=%u, Checksum=%04x", workOffset-1, buff.w[256] ); + + // + // Continuation... + // + if( buff.b[0] != (workCount-0) ) + { + log( 0, "Continue Fault: Received=%d, Expected=%d", buff.b[0], workCount ); + workCount = 0; + continue; + } + } + else + { + // + // New Command... + // + if( (crc = checksum( &buff.w[0], 3 )) != buff.w[3] ) + { + log( 0, "Bad Command Checksum: %02x %02x %02x %02x %02x %02x %02x %02x, Checksum=%04x", + buff.b[0], buff.b[1], buff.b[2], buff.b[3], buff.b[4], buff.b[5], buff.b[6], buff.b[7], crc); + continue; + } + + img = (buff.inquire.driveAndHead & ATA_DriveAndHead_Drive) ? image1 : image0; + + workCommand = buff.chs.command & SERIAL_COMMAND_RWMASK; + + if( (workCommand != SERIAL_COMMAND_INQUIRE) && (buff.chs.driveAndHead & ATA_COMMAND_LBA) ) + { + mylba = ((((unsigned long) buff.lba.bits24) & ATA_COMMAND_HEADMASK) << 24) + | (((unsigned long) buff.lba.bits16) << 16) + | (((unsigned long) buff.lba.bits08) << 8) + | ((unsigned long) buff.lba.bits00); + } + else + { + cyl = buff.chs.cylinder; + sect = buff.chs.sector; + head = (buff.chs.driveAndHead & ATA_COMMAND_HEADMASK); + mylba = img ? (((cyl*img->head + head)*img->sect) + sect-1) : 0; + } + + workOffset = 0; + workCount = buff.chs.count; + + if( verboseLevel > 0 ) + { + const char *comStr = (workCommand & SERIAL_COMMAND_WRITE ? "Write" : "Read"); + + if( workCommand == SERIAL_COMMAND_INQUIRE ) + log( 1, "Inquire %d: Client Port=0x%x, Client Baud=%s", img == image0 ? 0 : 1, + ((unsigned short) buff.inquire.port) << 2, + baudRateMatchDivisor( buff.inquire.baud )->display ); + else if( buff.chs.driveAndHead & ATA_COMMAND_LBA ) + log( 1, "%s %d: LBA=%u, Count=%u", comStr, img == image0 ? 0 : 1, + mylba, workCount ); + else + log( 1, "%s %d: Cylinder=%u, Sector=%u, Head=%u, Count=%u, LBA=%u", comStr, img == image0 ? 0 : 1, + cyl, sect, head, workCount, mylba ); + } + + if( !img ) + { + log( 1, " No slave drive provided" ); + workCount = 0; + continue; + } + + if( (workCommand & SERIAL_COMMAND_WRITE) && img->readOnly ) + { + log( 1, " Write attempt to Read Only disk" ); + workCount = 0; + continue; + } + + if( verboseLevel > 0 && workCount > 100 ) + perfTimer = GetTime(); + } + + if( workCount && (workCommand == (SERIAL_COMMAND_WRITE | SERIAL_COMMAND_READWRITE)) ) + { + // + // Write command... Setup to receive a sector + // + readto = 514; + } + else + { + // + // Inquire command... + // + if( workCommand == SERIAL_COMMAND_INQUIRE ) + { + unsigned char localScan; + + if( serial->speedEmulation && + buff.inquire.baud != serial->baudRate->divisor ) + { + log( 1, " Ignoring Inquire with wrong baud rate" ); + workCount = 0; + continue; + } + + localScan = buff.inquire.scan; // need to do this before the call to + // img->respondInquire, as it will clear the buff + img->respondInquire( &buff.w[0], buff.inquirePacked.PackedPortAndBaud, + serial->baudRate, + ((unsigned short) buff.inquire.port) << 2, + (img == image1 && lastScan) || buff.inquire.scan ); + lastScan = localScan; + } + // + // Read command... + // + else + { + img->seekSector( mylba + workOffset ); + img->readSector( &buff.w[0] ); + lastScan = 0; + } + + buff.w[256] = checksum( &buff.w[0], 256 ); + + if( !serial->writeCharacters( &buff.w[0], 514 ) ) + break; + + if( verboseLevel >= 3 ) + logBuff( " Sending: ", 514, 514, verboseLevel ); + + workCount--; + workOffset++; + + if( workCount ) + readto = 1; // looking for continuation ACK + } + } + + if( workCount == 0 && workOffset > 100 ) + log( 1, " Performance: %.2lf bytes per second", (512.0 * workOffset) / (GetTime() - perfTimer) * 1000.0 ); + } +} + + diff --git a/lib/serial_server/library/Serial.cpp b/lib/serial_server/library/Serial.cpp new file mode 100644 index 000000000..cae1d2976 --- /dev/null +++ b/lib/serial_server/library/Serial.cpp @@ -0,0 +1,71 @@ +//====================================================================== +// +// Project: XTIDE Universal BIOS, Serial Port Server +// +// File: Serial.cpp - Generic functions for dealing with serial communications +// + +// +// XTIDE Universal BIOS and Associated Tools +// Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// + +#include "Library.h" +#include +#include + +struct baudRate supportedBaudRates[] = +{ + { 2400, 0x30, "2400", B2400 }, + { 4800, 0x18, "4800", B4800 }, + { 9600, 0xc, "9600", B9600 }, + { 19200, 0xff, "19.2K", B19200 }, +//{ 28800, 0x4, "28.8K", B28800 }, + { 38400, 0xff, "38.4K", B38400 }, + { 57600, 0x2, "57.6K", B57600 }, +//{ 76800, 0xff, "76.8K", B76800 }, + { 115200, 0x1, "115.2K", B115200 }, +//{ 153600, 0xff, "153.6K", B153600 }, + { 230400, 0xff, "230.4K", B230400 }, + { 460800, 0xff, "460.8K", B460800 }, + { 921600, 0xff, "921.6K", B921600 }, + { 0, 0, "Unknown", 0 }, +}; + +struct baudRate *baudRateMatchString( const char *str ) +{ + struct baudRate *b; + + unsigned long a = atol( str ); + if( a ) + { + for( b = supportedBaudRates; b->rate; b++ ) + if( b->rate == a || (b->rate / 1000) == a || ((b->rate + 500) / 1000) == a ) + return( b ); + } + + return( b ); +} + +struct baudRate *baudRateMatchDivisor( unsigned char divisor ) +{ + struct baudRate *b; + + for( b = supportedBaudRates; b->rate && b->divisor != divisor; b++ ) + ; + + return( b ); +} + + diff --git a/menu.cpp b/menu.cpp index 3ad06e352..73e4d664a 100644 --- a/menu.cpp +++ b/menu.cpp @@ -2266,6 +2266,11 @@ void HandleUI(void) char idx = user_io_ext_idx(selPath, fs_pFileExt) << 6 | ioctl_index; if (addon[0] == 'f' && addon[1] != '1') process_addon(addon, idx); + if (is_pcxt()) + { + pcxt_set_image(selPath); + } + if (is_x86()) { x86_set_image(ioctl_index, selPath); diff --git a/support.h b/support.h index 65d11bbbe..c2f21383b 100644 --- a/support.h +++ b/support.h @@ -11,6 +11,9 @@ // Archie support #include "support/archie/archie.h" +// PCXT support +#include "support/pcxt/pcxt.h" + // ST (Atari) support #include "support/st/st_tos.h" diff --git a/support/pcxt/pcxt.cpp b/support/pcxt/pcxt.cpp new file mode 100644 index 000000000..d02aae462 --- /dev/null +++ b/support/pcxt/pcxt.cpp @@ -0,0 +1,139 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "../../hardware.h" +#include "../../fpga_io.h" +#include "../../menu.h" +#include "../../debug.h" +#include "../../user_io.h" +#include "../../input.h" +#include "../../support.h" +#include "../../lib/serial_server/library/Library.h" +#include "../../lib/serial_server/library/FlatImage.h" +#include "pcxt.h" + +int verbose = 0; + +char imagepath[512]; +int timeoutEnabled = 1; +//char* baudRate = NULL; +unsigned long cyl = 0, sect = 0, head = 0; +int readOnly = 0, createFile = 0; +int useCHS = 0; + + +void pcxt_init() +{ + user_io_status_set("[0]", 1); + const char* home = HomeDir(); + static char mainpath[512]; + + // legacy style of rom + sprintf(mainpath, "%s/boot.rom", home); + user_io_file_tx(mainpath); +} + +void pcxt_set_image(char *selPath) +{ + const char* imghome = "/media/fat"; + + pthread_t uart_thread; + + sprintf(imagepath, "%s/%s", imghome, selPath); + + //sprintf(baudRate, "460800"); + cyl = 62; + sect = 63; + head = 16; + + pthread_create(&uart_thread, NULL, OpenUART, NULL); +} + + + + +void* OpenUART(void* uartarg) { + + SerialAccess serial; + + char ComPortBuff[20]; + sprintf(ComPortBuff, "/dev/ttyS1"); + const char* ComPort = NULL; + ComPort = &ComPortBuff[0]; + + struct baudRate* baudRate = NULL; + baudRate = baudRateMatchString("460800"); + + int imagecount = 0; + Image* images[2] = { NULL, NULL }; + int timeoutEnabled = 1; + + images[0] = new FlatImage(imagepath, readOnly, imagecount, createFile, cyl, head, sect, useCHS); + + do + { + serial.Connect(ComPort, baudRate); + + processRequests(&serial, images[0], images[1], timeoutEnabled, verbose); + + serial.Disconnect(); + + if (serial.resetConnection) + log(0, "Serial Connection closed, reset..."); + } while (serial.resetConnection); + + + pthread_exit(NULL); +} + + + +void log(int level, const char* message, ...) +{ + va_list args; + + va_start(args, message); + + if (level < 0) + { + fprintf(stderr, "ERROR: "); + vfprintf(stderr, message, args); + fprintf(stderr, "\n"); + if (level < -1) + { + fprintf(stderr, "\n"); + //usage(); + } + //exit(1); + } + else if (verbose >= level) + { + vprintf(message, args); + printf("\n"); + } + + va_end(args); +} + + +unsigned long GetTime(void) +{ + struct timespec now; + + + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return 0; + return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0; +} + +unsigned long GetTime_Timeout(void) +{ + return(1000); +} diff --git a/support/pcxt/pcxt.h b/support/pcxt/pcxt.h new file mode 100644 index 000000000..0449edb16 --- /dev/null +++ b/support/pcxt/pcxt.h @@ -0,0 +1,13 @@ +#ifndef PCXT_H +#define PCXT_H + +#include "../../file_io.h" + +void pcxt_init(void); +void pcxt_set_image(char* selPath); +void* OpenUART(void* uartarg); +void log(int level, const char* message, ...); +unsigned long GetTime(void); +unsigned long GetTime_Timeout(void); + +#endif // PCXT_H \ No newline at end of file diff --git a/user_io.cpp b/user_io.cpp index d6e075a28..9f5162178 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -255,6 +255,13 @@ char is_archie() return (is_archie_type == 1); } +static int is_pcxt_type = 0; +char is_pcxt() +{ + if (!is_pcxt_type) is_pcxt_type = strcasecmp(orig_name, "PCXT") ? 2 : 1; + return (is_pcxt_type == 1); +} + static int is_gba_type = 0; char is_gba() { @@ -1396,6 +1403,11 @@ void user_io_init(const char *path, const char *xml) printf("Identified Archimedes core"); archie_init(); } + else if (is_pcxt()) + { + printf("Identified PCXT core"); + pcxt_init(); + } else { const char *home = HomeDir(); diff --git a/user_io.h b/user_io.h index ffc35e5d5..802348ffc 100644 --- a/user_io.h +++ b/user_io.h @@ -275,6 +275,7 @@ char is_st(); char is_psx(); char is_arcade(); char is_saturn(); +char is_pcxt(); #define HomeDir(x) user_io_get_core_path(x) #define CoreName user_io_get_core_name()