|
40 | 40 | #include <vector> |
41 | 41 | #include <thread> |
42 | 42 |
|
| 43 | +//===================================================================== |
| 44 | +// Helper function: Calculate NMEA-0183 checksum |
| 45 | +//===================================================================== |
| 46 | +/** |
| 47 | + * @brief Calculate NMEA-0183 checksum (XOR of all characters between $ and *) |
| 48 | + * @param sentence NMEA sentence without $ prefix and * suffix |
| 49 | + * @return Checksum as 2-digit uppercase hex string |
| 50 | + */ |
| 51 | +std::string calculateNmeaChecksum( std::string_view sentence ) |
| 52 | +{ |
| 53 | + uint8_t checksum = 0; |
| 54 | + for( char c : sentence ) |
| 55 | + { |
| 56 | + checksum ^= static_cast<uint8_t>( c ); |
| 57 | + } |
| 58 | + |
| 59 | + char result[3]; |
| 60 | + std::snprintf( result, sizeof( result ), "%02X", checksum ); |
| 61 | + return std::string{ result }; |
| 62 | +} |
| 63 | + |
43 | 64 | int main() |
44 | 65 | { |
45 | 66 | using namespace nfx::string; |
@@ -619,10 +640,145 @@ int main() |
619 | 640 | } |
620 | 641 |
|
621 | 642 | //===================================================================== |
622 | | - // 15. Prepend operations - Building strings in reverse |
| 643 | + // 15. Line-based operations - appendLine() / appendLn() |
| 644 | + //===================================================================== |
| 645 | + { |
| 646 | + std::cout << "15. Line-based operations - appendLine() / appendLn()\n"; |
| 647 | + std::cout << "------------------------------------------------------\n"; |
| 648 | + |
| 649 | + // Basic line appending |
| 650 | + std::cout << "Basic line appending:\n"; |
| 651 | + { |
| 652 | + StringBuilder builder; |
| 653 | + builder.appendLine( "First line" ).appendLine( "Second line" ).appendLine( "Third line" ); |
| 654 | + |
| 655 | + std::cout << " Result:\n" << builder.toString(); |
| 656 | + std::cout << " Note: Each appendLine() adds '\\n' automatically\n"; |
| 657 | + std::cout << "\n"; |
| 658 | + } |
| 659 | + |
| 660 | + // Building CSV-like data |
| 661 | + std::cout << "Building CSV-like data:\n"; |
| 662 | + { |
| 663 | + StringBuilder builder; |
| 664 | + builder.appendLine( "Name,Age,City" ) |
| 665 | + .appendLine( "Alice,30,Paris" ) |
| 666 | + .appendLine( "Bob,25,London" ) |
| 667 | + .appendLine( "Charlie,35,Berlin" ); |
| 668 | + |
| 669 | + std::cout << " Result:\n" << builder.toString(); |
| 670 | + std::cout << "\n"; |
| 671 | + } |
| 672 | + |
| 673 | + std::cout << "Building NMEA-0183 messages with checksums:\n"; |
| 674 | + { |
| 675 | + StringBuilder builder; |
| 676 | + |
| 677 | + // Helper lambda to build NMEA sentence with checksum |
| 678 | + auto buildNmeaSentence = [&builder]( std::string_view sentence ) { |
| 679 | + builder.append( "$" ).append( sentence ); |
| 680 | + std::string checksum = calculateNmeaChecksum( sentence ); |
| 681 | + builder.append( "*" ).append( checksum ); |
| 682 | + builder.appendLine(); |
| 683 | + }; |
| 684 | + |
| 685 | + // GPS Fix Data (GPGGA) |
| 686 | + buildNmeaSentence( "GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,," ); |
| 687 | + |
| 688 | + // GPS DOP and active satellites (GPGSA) |
| 689 | + buildNmeaSentence( "GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1" ); |
| 690 | + |
| 691 | + // Satellites in view (GPGSV) |
| 692 | + buildNmeaSentence( "GPGSV,2,1,08,01,40,083,46,02,17,308,41,12,07,344,39,14,22,228,45" ); |
| 693 | + |
| 694 | + // Meteorological Composite (WIMDA) - Full message |
| 695 | + buildNmeaSentence( "WIMDA,29.92,I,1.013,B,15.5,C,10.2,C,45.0,,12.5,C,270.0,T,270.0,M,5.2,N,2.7,M" ); |
| 696 | + |
| 697 | + // Wind Speed and Angle (WIMWV) |
| 698 | + buildNmeaSentence( "WIMWV,270.0,T,5.2,N,A" ); |
| 699 | + |
| 700 | + // Water Temperature (WIMTW) |
| 701 | + buildNmeaSentence( "WIMTW,10.2,C" ); |
| 702 | + |
| 703 | + std::cout << " Result:\n" << builder.toString(); |
| 704 | + std::cout << " Note: All messages include valid NMEA-0183 checksums\n"; |
| 705 | + std::cout << " Format: $SENTENCE*XX where XX is XOR checksum\n"; |
| 706 | + std::cout << "\n"; |
| 707 | + } |
| 708 | + |
| 709 | + // Building a realistic NMEA-0183 data stream |
| 710 | + std::cout << "Building realistic NMEA-0183 data stream:\n"; |
| 711 | + { |
| 712 | + StringBuilder builder; |
| 713 | + |
| 714 | + // Simulate a GPS/Weather station output |
| 715 | + auto addNmea = [&builder]( std::string_view sentence ) { |
| 716 | + builder.append( "$" ).append( sentence ); |
| 717 | + builder.append( "*" ).append( calculateNmeaChecksum( sentence ) ); |
| 718 | + builder.appendLine(); |
| 719 | + }; |
| 720 | + |
| 721 | + // Position update |
| 722 | + addNmea( "GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W" ); |
| 723 | + addNmea( "GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,," ); |
| 724 | + |
| 725 | + // Weather data |
| 726 | + addNmea( "WIMDA,30.12,I,1.020,B,18.3,C,12.5,C,52.0,,10.8,C,285.0,T,285.0,M,12.5,N,6.4,M" ); |
| 727 | + addNmea( "WIMWV,285.0,T,12.5,N,A" ); |
| 728 | + |
| 729 | + // Depth sounder |
| 730 | + addNmea( "SDDBT,45.2,f,13.8,M,7.5,F" ); |
| 731 | + |
| 732 | + std::cout << " Result:\n" << builder.toString(); |
| 733 | + std::cout << "\n"; |
| 734 | + } |
| 735 | + |
| 736 | + // Building log entries |
| 737 | + std::cout << "Building multi-line log entries:\n"; |
| 738 | + { |
| 739 | + StringBuilder builder; |
| 740 | + |
| 741 | + auto now = std::chrono::system_clock::now(); |
| 742 | + auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>( now.time_since_epoch() ).count(); |
| 743 | + |
| 744 | + builder.appendLine( "[INFO] Application started" ) |
| 745 | + .append( "[DEBUG] Timestamp: " ) |
| 746 | + .append( timestamp ) |
| 747 | + .appendLine() |
| 748 | + .appendLine( "[INFO] Configuration loaded" ) |
| 749 | + .appendLine( "[WARN] Cache not found, creating new" ); |
| 750 | + |
| 751 | + std::cout << " Result:\n" << builder.toString(); |
| 752 | + std::cout << "\n"; |
| 753 | + } |
| 754 | + |
| 755 | + // Building JSON-like structure (simplified) |
| 756 | + std::cout << "Building structured text:\n"; |
| 757 | + { |
| 758 | + StringBuilder builder; |
| 759 | + builder.appendLine( "{" ) |
| 760 | + .appendLine( " \"name\": \"StringBuilder\"," ) |
| 761 | + .appendLine( " \"version\": \"0.5.0\"," ) |
| 762 | + .appendLine( " \"features\": [" ) |
| 763 | + .appendLine( " \"SBO\"," ) |
| 764 | + .appendLine( " \"Zero-copy\"," ) |
| 765 | + .appendLine( " \"High-performance\"" ) |
| 766 | + .appendLine( " ]" ) |
| 767 | + .appendLine( "}" ); |
| 768 | + |
| 769 | + std::cout << " Result:\n" << builder.toString(); |
| 770 | + std::cout << " Note: Indentation handled manually\n"; |
| 771 | + std::cout << "\n"; |
| 772 | + } |
| 773 | + |
| 774 | + std::cout << "\n"; |
| 775 | + } |
| 776 | + |
| 777 | + //===================================================================== |
| 778 | + // 16. Prepend operations - Building strings in reverse |
623 | 779 | //===================================================================== |
624 | 780 | { |
625 | | - std::cout << "15. Prepend operations - Building strings in reverse\n"; |
| 781 | + std::cout << "16. Prepend operations - Building strings in reverse\n"; |
626 | 782 | std::cout << "----------------------------------------------------\n"; |
627 | 783 |
|
628 | 784 | // Basic prepend |
|
0 commit comments