{"id":25448092,"url":"https://github.com/sindreoyen/nmeaparser","last_synced_at":"2026-05-20T07:31:29.059Z","repository":{"id":277348584,"uuid":"931666226","full_name":"sindreoyen/NMEAParser","owner":"sindreoyen","description":"A native-built NMEA parser for iOS and macOS applications.","archived":false,"fork":false,"pushed_at":"2025-03-01T16:59:38.000Z","size":230,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-13T07:05:51.933Z","etag":null,"topics":["geolocation","gga","gnss","gsv","ios","nmea","ntrip","package","rmc","rtcm","rtk","spm","swift","swift-library","swift-package","swift-package-manager","swift5","swift6","swiftui","xcode"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sindreoyen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-12T16:53:45.000Z","updated_at":"2025-03-01T16:59:09.000Z","dependencies_parsed_at":"2025-05-16T07:09:14.389Z","dependency_job_id":"8e034ee7-3407-4e8f-a325-30f4a5bad6a2","html_url":"https://github.com/sindreoyen/NMEAParser","commit_stats":null,"previous_names":["sindreoyen/nmeaparser"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/sindreoyen/NMEAParser","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindreoyen%2FNMEAParser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindreoyen%2FNMEAParser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindreoyen%2FNMEAParser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindreoyen%2FNMEAParser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sindreoyen","download_url":"https://codeload.github.com/sindreoyen/NMEAParser/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindreoyen%2FNMEAParser/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259599324,"owners_count":22882354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["geolocation","gga","gnss","gsv","ios","nmea","ntrip","package","rmc","rtcm","rtk","spm","swift","swift-library","swift-package","swift-package-manager","swift5","swift6","swiftui","xcode"],"created_at":"2025-02-17T19:18:47.094Z","updated_at":"2026-05-20T07:31:29.017Z","avatar_url":"https://github.com/sindreoyen.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"![NMEAParser logo](Resources/NMEAParserLogo-2.png)\n\n[![Swift](https://img.shields.io/badge/Swift-5.9_5.10_6.0-orange?style=flat-square)](https://img.shields.io/badge/Swift-5.9_5.10_6.0-Orange?style=flat-square)\n[![Platforms](https://img.shields.io/badge/Platforms-macOS_iOS_iPadOS-yellowgreen?style=flat-square)](https://img.shields.io/badge/Platforms-macOS_iOS-Green?style=flat-square)\n[![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)\n\nNMEAParser is a Swift package designed to validate and parse National Marine Electronics Association (NMEA) sentences in real time. It is a seamless bridge between your application and GNSS receivers, converting raw NMEA data into a Swift-friendly format—making real-time integration effortless.\n\n## 1 Features\n\n- [x] Swift Concurrency Support Back to iOS 13 and macOS 10.15\n- [x] Support for Swift 5 and 6\n- [x] Combine Support\n- [x] Checksum Validation \n- [x] Descriptions for Fix Types\n- [x] GGA Sentences\n- [x] RMC Sentences\n- [ ] GSV Sentences (coming!)\n\n## 2 Requirements\n\n| Platform                                             | Minimum Swift Version | Installation                                                                                                         | Status                   |\n| ---------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------ |\n| iOS 13.0+ / macOS 10.15+ | 5.9 / Xcode 15.0      | [Swift Package Manager](#swift-package-manager) | Fully Tested             |\n\n\n## 3 Installation\n\n### 3.1 Swift Package Manager\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.\n\nOnce you set up your Swift package, adding NMEAParser as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift` or the Package list in Xcode.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/sindreoyen/NMEAParser.git\", .upToNextMajor(from: \"1.0.2\"))\n]\n```\n\n## 4 Usage\n\n### 4.1 Configuring the Parser Instance\n\nYou can configure which GGA and RMC identifiers you want to include by changing the `supportedGGAIdentifiers` or `supportedRMCIdentifiers` properties of the `NMEAParserManager`. E.g., in your App file:\n\n```swift\nimport NMEAParser\n\n@main\nstruct YourApp: App {\n    // MARK: - Attributes\n    // some attributes\n    \n    // MARK: - Body\n    var body: some Scene {\n        WindowGroup { ContentView() }\n    }\n    \n    // MARK: - Init\n    init() {\n        NMEAParserManager.shared.supportedGGAIdentifiers = [.gnGGA, .gpGGA]\n        NMEAParserManager.shared.supportedRMCIdentifiers = [.gnRMC, .gpRMC]\n    }\n}\n```\n\nThe identifiers used will vary from one GNSS receiver to another. Here is a brief overview of the supported types:\n\n##### From `GGAData.Identifier`\n\n```swift\npublic enum Identifier: String, CaseIterable {\n    case gnGGA = \"$GNGGA\" // GGA sentence from GPS and GLONASS\n    case gpGGA = \"$GPGGA\" // GGA sentence from GPS\n    case glGGA = \"$GLGGA\" // GGA sentence from GLONASS\n    case gaGGA = \"$GAGGA\" // GGA sentence from GALILEO\n}\n```\n\n##### From  `RMCData.Identifier`\n```swift\npublic enum Identifier: String, CaseIterable {\n    case gnRMC = \"$GNRMC\" // RMC sentence from GPS and GLONASS\n    case gpRMC = \"$GPRMC\" // RMC sentence from GPS\n    case glRMC = \"$GLRMC\" // RMC sentence from GLONASS\n    case gaRMC = \"$GARMC\" // RMC sentence from GALILEO\n}\n```\n\n### 4.2 Parsing NMEA Sentences\n\nParsing NMEA sentences is processed by the `NMEAParserManager.shared` instance and has *one interface* that is used for whichever NMEA sentence you want to process. The filtering logic and sending the sentence into the correct parser is handled by the `NMEAParserManager`. For parsing, you have two options:\n\n1. Parse an NMEA sentence already in `String` format\n\n```swift\npublic func peripheral(_ peripheral: CBPeripheral,\n                           didUpdateValueFor characteristic: CBCharacteristic,\n                           error: Error?) {\n        if let error { print(error); return }\n        // Send the updated value of the characteristic to the NMEA parser\n        guard let nmeaSentence: String = someConverterMethod(characteristic.value) else { return }\n        NMEAParserManager.shared.process(sentence: nmeaSentence)\n    }\n```\n\n2. Parse a `Data?` instance (e.g., the value of your GNSS receiver's `CBCharacteristic`)\n\n```swift\npublic func peripheral(_ peripheral: CBPeripheral,\n                           didUpdateValueFor characteristic: CBCharacteristic,\n                           error: Error?) {\n        if let error { print(error); return }\n        // Send the updated value of the characteristic to the NMEA parser\n        //\n        // The default encoding for the `process` method is .ascii\n        NMEAParserManager.shared.process(sentence: characteristic.value, encoding: .ascii)\n    }\n```\n\n### 4.3 Listening to Parsed Data\n\n#### 4.3.1 GGA Sentences\n\nThe parsed GGA data will be exposed under two `AnyPublisher` instances (`ggaDataPublisher: AnyPublisher\u003cGGAData, Never\u003e` and `rawGGASentencePublisher: AnyPublisher\u003cString, Never\u003e`). These are available via `NMEAParserManager.shared`. *If you are unfamiliar with [The Combine Framework](https://developer.apple.com/documentation/combine) and its Subjects, Publishers, and Cancellables, please read the linked documentation.*\n\nExample with `ggaDataPublisher` (for in-app display and use of data):\n```swift\n@MainActor\nfunc startListeningForGGAData() {\n    ggaCancellable?.cancel()\n    ggaCancellable = NMEAParserManager.shared.ggaDataPublisher\n        .throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)\n        .sink { [weak self] ggaData in\n            guard let self else { return }\n            self.hdop = ggaData.hdop\n            self.ggaFixType = ggaData.fixType\n        }\n}\n```\n\nExample with `rawGGASentencePublisher` (e.g., for NTRIP Client functionality):\n\n```swift\nself.ggaCancellable = NMEAParserManager.shared.rawGGASentencePublisher\n                .throttle(for: .seconds(10),\n                          scheduler: DispatchQueue.global(qos: .background),\n                          latest: true)\n                .receive(on: DispatchQueue.global(qos: .background))\n                .sink { [weak self] ggaMessage in\n                    guard let self = self else { return }\n                    print(\"NTRIPClient: Sending GGA message: \\(ggaMessage)\")\n                    self.sendGGAToCaster(ggaMessage)\n                }\n```\n\n#### 4.3.2 RMC Sentences\n\nRMC data is subscribable via the `rmcDataPublisher: AnyPublisher\u003cRMCData, Never\u003e` property of the shared `NMEAParserManager` instance. \n\n    Note: RMC data is not currently exposed via a raw stream. The GGA raw stream is intended for sending to NTRIP casters (if applicable), RMC is rare for this purpose. If you have the need for a raw stream of RMC data, submit an issue and I will look into it asap.\n\n## 4.4 Communication\n\n- If you **find a bug**, open an issue here on GitHub. The more detail the better!\n\n## 5 Contributing\n\nContributions are welcome. To contribute, first open an issue where you explain the bug or feature in full detail. If you have performed the necessary changes, open a PR, and I will review it continuously. \n\n*note: pull requests will not be accepted if they do not follow an acceptable standard regarding documentation, test coverage, and code style. Use Swiftlint to validate code styling (see Makefile).*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindreoyen%2Fnmeaparser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsindreoyen%2Fnmeaparser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindreoyen%2Fnmeaparser/lists"}