/* * Copyright 2015 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.drivers; import java.io.IOException; /** * A parser for NMEA strings. Not currently tested - it was planned for use with * the UM7LT but wasn't eventually used. * * @author skeggsc */ public class NMEA { /** * Find the next end of a NMEA packet. (A CR-LN sequence.) * * @param bytes the byte array to search. * @param from the start of the section to search. * @param to the end of the section to search. * @return the index directly after the newline, or -1 if the packet end * cannot be found. */ public static int getPacketEnd(byte[] bytes, int from, int to) { while (from < to) { int cr = ByteFiddling.indexOf(bytes, from, to - 1, (byte) '\r'); if (cr == -1) { break; } if (bytes[cr + 1] == '\n') { return cr + 2; } from = cr + 1; } return -1; } /** * This parses out an NMEA packet into a series of sections. * * This is from the UM7LT. If this is wrong for another device, perhaps we * need multiple versions. * * @param nmea the NMEA string's byte array. * @param from the start of the byte section. * @param to the end of the byte section. * @return an array of the parsed-out chunks. * @throws IOException if the NMEA frame is malformed. */ public static byte[][] parse(byte[] nmea, int from, int to) throws IOException { if (to - from < 3 || nmea[from] != '$' || nmea[to - 2] != '\r' || nmea[to - 1] != '\n') { throw new IOException("NMEA frame broken."); } byte[][] parts = ByteFiddling.split(nmea, from + 1, to - 2, (byte) ','); byte[] chkpt = parts[parts.length - 1]; Integer actualsum = ByteFiddling.parseInt(chkpt, 1, chkpt.length); if (chkpt[0] != '*' || actualsum == null) { throw new IOException("NMEA checksum not found."); } int checksum = checksum(nmea, from + 1, to - 2 - chkpt.length); if (checksum != actualsum) { throw new IOException("NMEA checksum mismatch: " + actualsum + " calculated instead of " + checksum); } return parts; } private static int checksum(byte[] nmea, int start, int end) { byte out = 0; for (int i = start; i < end; i++) { out ^= nmea[i]; } return out; } }