/** * flash25 init function. * This function init a comunication channel and * try to read manufacturer id of serial memory, * then check if is equal to selected type. */ static bool flash25_pin_init(Flash25 *fd) { uint8_t device_id; uint8_t manufacturer; SPI_HW_INIT(); SS_ACTIVE(); /* * Send read id productor opcode on * comunication channel * TODO:controllare se ha senso */ kfile_putc(FLASH25_RDID, fd->channel); manufacturer = kfile_getc(fd->channel); device_id = kfile_getc(fd->channel); SS_INACTIVE(); if((FLASH25_MANUFACTURER_ID == manufacturer) && (FLASH25_DEVICE_ID == device_id)) return true; else return false; }
/* Process that reads from the USB port and writes to the UART port */ static void NORETURN usb_serial_process(void) { iptr_t type = proc_currentUserData(); KFile *in_fd = (type == USB_TO_SERIAL) ? &usb_port.fd : &ser_port.fd; KFile *out_fd = (type == USB_TO_SERIAL) ? &ser_port.fd : &usb_port.fd; while (1) { int c; c = kfile_getc(in_fd); if (UNLIKELY(c == EOF)) { kfile_clearerr(in_fd); continue; } kfile_putc(c, out_fd); /* * Toggle the STAT LED when some data passes through the * usb-seral link */ LED_TOGGLE(); } }
/** * Read a line long at most as size and put it * in buf, with optional echo. * * \return number of chars read, or EOF in case * of error. */ int kfile_gets_echo(struct KFile *fd, char *buf, int size, bool echo) { int i = 0; int c; for (;;) { if ((c = kfile_getc(fd)) == EOF) { buf[i] = '\0'; return -1; } /* FIXME */ if (c == '\r' || c == '\n' || i >= size-1) { buf[i] = '\0'; if (echo) kfile_print(fd, "\r\n"); break; } buf[i++] = c; if (echo) kfile_putc(c, fd); } return i; }
/** * Receive the tag message from channel, and if * the tag is good put the converted string into given buffer. * The fuction return the len of found tag string, otherwise EOF. */ int keytag_recv(struct TagPacket *pkt, uint8_t *tag, size_t len) { int c; /* Get all chars from buffer */ while ((c = kfile_getc(pkt->tag)) != EOF) { /* Search for STX char in received chars */ if (c == TAG_STX) { /* When STX is found a new packet begins */ if (pkt->sync) LOG_WARN("TAG double sync!\n"); keytag_clearPkt(pkt); pkt->sync = true; } else if (pkt->sync) { /* Check for end of packet */ if (c == TAG_ETX) { /* Terminate the tag string */ size_t tag_len = MIN(len, pkt->len); /* Save read tag */ memcpy(tag, pkt->buf, tag_len); pkt->sync = false; return tag_len; } else { /* Check for buffer overflow */ if (pkt->len >= CONFIG_TAG_MAX_LEN) { LOG_ERR("TAG buffer overflow\n"); pkt->sync = false; } else { /* Add every char after STX to tag reading buffer */ if (pkt->sync) { pkt->buf[pkt->len] = c; pkt->len++; } } } } } if (kfile_error(pkt->tag) != 0) { LOG_ERR("Error %04x\n", kfile_error(pkt->tag)); kfile_clearerr(pkt->tag); } return EOF; }
/** * Discard input to resynchronize with remote end. * * Discard incoming data until the kfile_getc stops receiving * characters for at least \a delay milliseconds. * * \note If the timeout occur, we reset the error before to * quit. */ void kfile_resync(KFile *fd, mtime_t delay) { ticks_t start_time = timer_clock(); for(;;) { if(kfile_getc(fd) != EOF) start_time = timer_clock(); if ((timer_clock() - start_time) > ms_to_ticks(delay)) { kfile_clearerr(fd); break; } } }
int8_t gsmSMSSend(const char *number, const char *message) { int8_t resp, i; char buff[32]; gsmDebug("Sending SMS\n"); #if 0 if (strlen(message)>160) message[160] = 0; #else #warning CHECK for message max length!!! #endif // Sending destination number sprintf(buff, "AT+CMGS=\"%s\", 145", number); _gsmWriteLine(buff); DELAY(1000); //_gsmWrite("AT+CMGS=\"", 9); //_gsmWrite(number, strlen(number)); //_gsmWriteLine("\", 145"); // Wait for modem message prompt //_gsmRead(buff, 32); for (i=0; i<15; i++) { (*buff) = kfile_getc(&(gsm->fd)); if ((*buff) == EOF) return -1; if ((*buff) == '>') break; } if (i == 15) return -1; // Sending message _gsmWriteLine(message); DELAY(1000); // Sending terminator _gsmWriteLine("\x1a"); // Waiting send confirmation _gsmRead(buff, 32); resp = _gsmReadResult(); return resp; }
/** * Wait until flash memory is ready. */ static void flash25_waitReady(Flash25 *fd) { uint8_t stat; while (1) { SS_ACTIVE(); kfile_putc(FLASH25_RDSR, fd->channel); stat = kfile_getc(fd->channel); SS_INACTIVE(); if (!(stat & RDY_BIT)) break; cpu_relax(); } }
//////////////////////////////////////////////////////////// // The Poll function reads data from the modem, handles // // frame recognition and passes data on to higher layers // // if valid packets are found // //////////////////////////////////////////////////////////// void mp1Poll(MP1 *mp1) { int byte; // A place to store our read byte // Read bytes from the modem until we reach EOF while ((byte = kfile_getc(mp1->modem)) != EOF) { // We read something from the modem, so we // set the settleTimer mp1->settleTimer = timer_clock(); ///////////////////////////////////////////// // This following block handles forward // // error correction using an interleaved // // (12,8) Hamming code // ///////////////////////////////////////////// // If we have started reading (received an // HDLC_FLAG), we will start looking at the // incoming data and perform forward error // correction on it. if ((mp1->reading && (byte != AX25_ESC )) || (mp1->reading && (mp1->escape && (byte == AX25_ESC || byte == HDLC_FLAG || byte == HDLC_RESET)))) { // We have a byte, increment our read counter mp1->readLength++; // Check if we have read three bytes. If we // have, we should now have a block of two // data bytes and a parity byte. This block if (mp1->readLength % MP1_INTERLEAVE_SIZE == 0) { // If the last character in the block // looks like a control character, we // need to set the escape indicator to // false, since the next byte will be // read immediately after the FEC // routine, and thus, the normal reading // code will not reset the indicator. if (byte == AX25_ESC || byte == HDLC_FLAG || byte == HDLC_RESET) mp1->escape = false; // The block is interleaved, so we will // first put the received bytes in the // deinterleaving buffer for (int i = 1; i < MP1_INTERLEAVE_SIZE; i++) { mp1->interleaveIn[i-1] = mp1->buffer[mp1->packetLength-(MP1_INTERLEAVE_SIZE-i)]; } mp1->interleaveIn[MP1_INTERLEAVE_SIZE-1] = byte; // We then deinterleave the block mp1Deinterleave(mp1); // Adjust the packet length, since we will get // parity bytes in the data buffer with block // sizes larger than 3 mp1->packetLength -= MP1_INTERLEAVE_SIZE/3 - 1; // For each 3-byte block in the deinterleaved // bytes, we apply forward error correction for (int i = 0; i < MP1_INTERLEAVE_SIZE; i+=3) { // We now calculate a parity byte on the // received data. // Deinterleaved data bytes uint8_t a = mp1->interleaveIn[i]; uint8_t b = mp1->interleaveIn[i+1]; // Deinterleaved parity byte uint8_t p = mp1->interleaveIn[i+2]; mp1->calculatedParity = mp1ParityBlock(a, b); // By XORing the calculated parity byte // with the received parity byte, we get // what is called the "syndrome". This // number will tell us if we had any // errors during transmission, and if so // where they are. Using Hamming code, we // can only detect single bit errors in a // byte though, which is why we interleave // the data, since most errors will usually // occur in bursts of more than one bit. // With 2 data byte interleaving we can // correct 2 consecutive bit errors. uint8_t syndrome = mp1->calculatedParity ^ p; if (syndrome == 0x00) { // If the syndrome equals 0, we either // don't have any errors, or the error // is unrecoverable, so we don't do // anything } else { // If the syndrome is not equal to 0, // there is a problem, and we will try // to correct it. We first need to split // the syndrome byte up into the two // actual syndrome numbers, one for // each data byte. uint8_t syndromes[2]; syndromes[0] = syndrome & 0x0f; syndromes[1] = (syndrome & 0xf0) >> 4; // Then we look at each syndrome number // to determine what bit in the data // bytes to correct. for (int i = 0; i < 2; i++) { uint8_t s = syndromes[i]; uint8_t correction = 0x00; if (s == 1 || s == 2 || s == 4 || s == 8) { // This signifies an error in the // parity block, so we actually // don't need any correction continue; } // The following determines what // bit to correct according to // the syndrome value. if (s == 3) correction = 0x01; if (s == 5) correction = 0x02; if (s == 6) correction = 0x04; if (s == 7) correction = 0x08; if (s == 9) correction = 0x10; if (s == 10) correction = 0x20; if (s == 11) correction = 0x40; if (s == 12) correction = 0x80; // And finally we apply the correction if (i == 1) a ^= correction; if (i == 0) b ^= correction; // This is just for testing purposes. // Nice to know when corrections were // actually made. if (s != 0) mp1->correctionsMade += 1; } } // We now update the checksum of the packet // with the deinterleaved and possibly // corrected bytes. mp1->checksum_in ^= a; mp1->checksum_in ^= b; mp1->buffer[mp1->packetLength-(MP1_DATA_BLOCK_SIZE)+((i/3)*2)] = a; mp1->buffer[mp1->packetLength-(MP1_DATA_BLOCK_SIZE-1)+((i/3)*2)] = b; } continue; } } ///////////////////////////////////////////// // End of forward error correction block // ///////////////////////////////////////////// // This next part of the poll function handles // the reading from the modem, and looks for // starts and ends of transmissions. It also // handles escape characters by discarding them // so they don't get put into the output data. // Let's first check if we have read an HDLC_FLAG. if (!mp1->escape && byte == HDLC_FLAG) { // We are not in an escape sequence and we // found a HDLC_FLAG. This can mean two things: if (mp1->readLength >= MP1_MIN_FRAME_LENGTH) { // We already have more data than the minimum // frame length, which means the flag signifies // the end of the packet. Pass control to the // decoder. // // We also set the settle timer to indicate // the time the frame completed reading. mp1->settleTimer = timer_clock(); if ((mp1->checksum_in & 0xff) == 0x00) { if (SERIAL_DEBUG) kprintf("[CHK-OK] [C=%d] ", mp1->correctionsMade); mp1Decode(mp1); } else { // Checksum was incorrect, we don't do anything, // but you can enable the decode anyway, if you // need it for testing or debugging if (PASSALL) { if (SERIAL_DEBUG) kprintf("[CHK-ER] [C=%d] ", mp1->correctionsMade); mp1Decode(mp1); } } } // If the above is not the case, this must be the // beginning of a frame mp1->reading = true; mp1->packetLength = 0; mp1->readLength = 0; mp1->checksum_in = MP1_CHECKSUM_INIT; mp1->correctionsMade = 0; // We have indicated that we are reading, // and reset the length counter. Now we'll // continue to the next byte. continue; } if (!mp1->escape && byte == HDLC_RESET) { // Not good, we got a reset. The transmitting // party may have encountered an error. We'll // stop receiving this packet immediately. mp1->reading = false; continue; } if (!mp1->escape && byte == AX25_ESC) { // We found an escape character. We'll set // the escape seqeunce indicator so we don't // interpret the next byte as a reset or flag mp1->escape = true; // We then continue reading the next byte. continue; } // Now let's get to the actual reading of the data if (mp1->reading) { if (mp1->packetLength < MP1_MAX_FRAME_LENGTH + MP1_INTERLEAVE_SIZE) { // If the length of the current incoming frame is // still less than our max length, put the incoming // byte in the buffer. When we have collected 3 // bytes, they will be processed by the error // correction part above. mp1->buffer[mp1->packetLength++] = byte; } else { // If not, we have a problem: The buffer has overrun // We need to stop receiving, and the packet will be // dropped :( mp1->reading = false; } } // We need to set the escape sequence indicator back // to false after each byte. mp1->escape = false; }
/** * Try to read a packet from the pocketBus. * \return true if a packet is received, false otherwise. */ bool pocketbus_recv(struct PocketBusCtx *ctx, struct PocketMsg *msg) { int c; /* Process incoming characters until buffer is not empty */ while ((c = kfile_getc(ctx->fd)) != EOF) { /* Look for STX char */ if (c == POCKETBUS_STX && !ctx->escape) { /* When an STX is found, inconditionally start a new packet */ if (ctx->sync) kprintf("pocketBus double sync!\n"); ctx->sync = true; ctx->len = 0; rotating_init(&ctx->in_cks); continue; } if (ctx->sync) { /* Handle escape mode */ if (c == POCKETBUS_ESC && !ctx->escape) { ctx->escape = true; continue; } /* Handle message end */ if (c == POCKETBUS_ETX && !ctx->escape) { ctx->sync = false; /* Check minimum size */ if (ctx->len < sizeof(PocketBusHdr) + sizeof(rotating_t)) { kprintf("pocketBus short pkt!\n"); continue; } /* Remove checksum bytes from packet len */ ctx->len -= sizeof(rotating_t); /* Compute checksum */ rotating_update(ctx->buf, ctx->len, &ctx->in_cks); uint8_t cks_h = *(ctx->buf + ctx->len); uint8_t cks_l = *(ctx->buf + ctx->len + 1); rotating_t recv_cks = (cks_h << 8) | cks_l; /* Checksum check */ if (recv_cks == ctx->in_cks) { PocketBusHdr *hdr = (PocketBusHdr *)ctx; /* Check packet version */ if (hdr->ver == POCKETBUS_VER) { /* Packet received, set msg fields */ msg->payload = ctx->buf + sizeof(PocketBusHdr); msg->addr = be16_to_cpu(hdr->addr); msg->len = ctx->len - sizeof(PocketBusHdr); msg->ctx = ctx; return true; } else { kprintf("pocketBus version mismatch, here[%d], there[%d]\n", POCKETBUS_VER, hdr->ver); continue; } } else { kprintf("pocketBus cks error, here[%04X], there[%04X]\n", ctx->in_cks, recv_cks); continue; } } ctx->escape = false; /* Check buffer overflow: simply ignore received data and go to unsynced state. */ if (ctx->len >= CONFIG_POCKETBUS_BUFLEN) { kprintf("pocketBus buffer overflow\n"); ctx->sync = false; continue; } /* Put received data in the buffer */ ctx->buf[ctx->len] = c; ctx->len++; } } /* * Check stream status. */ if (kfile_error(ctx->fd)) { LOG_ERR("fd status[%04X]\n", kfile_error(ctx->fd)); kfile_clearerr(ctx->fd); } return false; }
/** * \brief Receive a file using the XModem protocol. * * \param ch Channel to use for transfer * \param fd Destination file * * \note This function allocates a large amount of stack (\see XM_BUFSIZE). */ bool xmodem_recv(KFile *ch, KFile *fd) { char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */ int c, i, blocksize; int blocknr = 0, last_block_done = 0, retries = 0; char *buf; uint8_t checksum; uint16_t crc; bool purge = false; bool usecrc = true; LOG_INFO("Starting Transfer...\n"); purge = true; kfile_clearerr(ch); /* Send initial NAK to start transmission */ for(;;) { if (XMODEM_CHECK_ABORT) { kfile_putc(XM_CAN, ch); kfile_putc(XM_CAN, ch); LOG_INFO("Transfer aborted\n"); return false; } /* * Discard incoming input until a timeout occurs, then send * a NAK to the transmitter. */ if (purge) { purge = false; if (kfile_error(ch)) { LOG_ERR("Retries %d\n", retries); } kfile_resync(ch, 200); retries++; if (retries >= CONFIG_XMODEM_MAXRETRIES) { kfile_putc(XM_CAN, ch); kfile_putc(XM_CAN, ch); LOG_INFO("Transfer aborted\n"); return false; } /* Transmission start? */ if (blocknr == 0) { if (retries < CONFIG_XMODEM_MAXCRCRETRIES) { LOG_INFO("Request Tx (CRC)\n"); kfile_putc(XM_C, ch); } else { /* Give up with CRC and fall back to checksum */ usecrc = false; LOG_INFO("Request Tx (BCC)\n"); kfile_putc(XM_NAK, ch); } } else kfile_putc(XM_NAK, ch); } switch (kfile_getc(ch)) { #if XM_BUFSIZE >= 1024 case XM_STX: /* Start of header (1024-byte block) */ blocksize = 1024; goto getblock; #endif case XM_SOH: /* Start of header (128-byte block) */ blocksize = 128; /* Needed to avoid warning if XM_BUFSIZE < 1024 */ getblock: /* Get block number */ c = kfile_getc(ch); /* Check complemented block number */ if ((~c & 0xff) != kfile_getc(ch)) { LOG_WARN("Bad blk (%d)\n", c); purge = true; break; } /* Determine which block is being sent */ if (c == (blocknr & 0xff)) { /* Last block repeated */ LOG_INFO("Repeat blk %d\n", blocknr); } else if (c == ((blocknr + 1) & 0xff)) { /* Next block */ LOG_INFO("Recv blk %d\n", ++blocknr); } else { /* Sync lost */ LOG_WARN("Sync lost (%d/%d)\n", c, blocknr); purge = true; break; } buf = block_buffer; /* Reset pointer to start of buffer */ checksum = 0; crc = 0; for (i = 0; i < blocksize; i++) { if ((c = kfile_getc(ch)) == EOF) { purge = true; break; } /* Store in buffer */ *buf++ = (char)c; /* Calculate block checksum or CRC */ if (usecrc) crc = UPDCRC16(c, crc); else checksum += (char)c; } if (purge) break; /* Get the checksum byte or the CRC-16 MSB */ if ((c = kfile_getc(ch)) == EOF) { purge = true; break; } if (usecrc) { crc = UPDCRC16(c, crc); /* Get CRC-16 LSB */ if ((c = kfile_getc(ch)) == EOF) { purge = true; break; } crc = UPDCRC16(c, crc); if (crc) { LOG_ERR("Bad CRC: %04x\n", crc); purge = true; break; } } /* Compare the checksum */ else if (c != checksum) { LOG_ERR("Bad sum: %04x/%04x\n", checksum, c); purge = true; break; } /* * Avoid flushing the same block twice. * This could happen when the sender does not receive our * acknowledge and resends the same block. */ if (last_block_done < blocknr) { /* Call user function to flush the buffer */ if (kfile_write(fd, block_buffer, blocksize)) { /* Acknowledge block and clear error counter */ kfile_putc(XM_ACK, ch); retries = 0; last_block_done = blocknr; } else { /* User callback failed: abort transfer immediately */ retries = CONFIG_XMODEM_MAXRETRIES; purge = true; } } break; case XM_EOT: /* End of transmission */ kfile_putc(XM_ACK, ch); LOG_INFO("Transfer completed\n"); return true; case EOF: /* Timeout or serial error */ purge = true; break; default: LOG_INFO("Skipping garbage\n"); purge = true; break; } } /* End forever */ }
/** * \brief Transmit some data using the XModem protocol. * * \param ch Channel to use for transfer * \param fd Source file * * \note This function allocates a large amount of stack for * the XModem transfer buffer (\see XM_BUFSIZE). */ bool xmodem_send(KFile *ch, KFile *fd) { char block_buffer[XM_BUFSIZE]; /* Buffer to hold a block of data */ size_t size = -1; int blocknr = 1, retries = 0, c, i; bool proceed, usecrc = false; uint16_t crc; uint8_t sum; /* * Reading a block can be very slow, so we read the first block early * to avoid receiving double XM_C char. * This could happen if we check for XM_C and then read the block, giving * the receiving device time to send another XM_C char misinterpretating * the blocks sent. */ size = kfile_read(fd, block_buffer, XM_BUFSIZE); kfile_clearerr(ch); LOG_INFO("Wait remote host\n"); for(;;) { proceed = false; do { if (XMODEM_CHECK_ABORT) return false; switch (c = kfile_getc(ch)) { case XM_NAK: LOG_INFO("Resend blk %d\n", blocknr); proceed = true; break; case XM_C: if (c == XM_C) { LOG_INFO("Tx start (CRC)\n"); usecrc = true; } else { LOG_INFO("Tx start (BCC)\n"); } proceed = true; break; case XM_ACK: /* End of transfer? */ if (!size) return true; /* Call user function to read in one block */ size = kfile_read(fd, block_buffer, XM_BUFSIZE); LOG_INFO("Send blk %d\n", blocknr); blocknr++; retries = 0; proceed = true; break; case EOF: kfile_clearerr(ch); retries++; LOG_INFO("Retries %d\n", retries); if (retries <= CONFIG_XMODEM_MAXRETRIES) break; /* falling through! */ case XM_CAN: LOG_INFO("Transfer aborted\n"); return false; default: LOG_INFO("Skipping garbage\n"); break; } } while (!proceed); if (!size) { kfile_putc(XM_EOT, ch); continue; } /* Pad block with 0xFF if it's partially full */ memset(block_buffer + size, 0xFF, XM_BUFSIZE - size); /* Send block header (STX, blocknr, ~blocknr) */ #if XM_BUFSIZE == 128 kfile_putc(XM_SOH, ch); #else kfile_putc(XM_STX, ch); #endif kfile_putc(blocknr & 0xFF, ch); kfile_putc(~blocknr & 0xFF, ch); /* Send block and compute its CRC/checksum */ sum = 0; crc = 0; for (i = 0; i < XM_BUFSIZE; i++) { kfile_putc(block_buffer[i], ch); crc = UPDCRC16(block_buffer[i], crc); sum += block_buffer[i]; } /* Send CRC/Checksum */ if (usecrc) { kfile_putc(crc >> 8, ch); kfile_putc(crc & 0xFF, ch); } else kfile_putc(sum, ch); }
/** * @return 1 if a valid message has been retrived, 0 on no valid message, -1 * on parsing error. */ int8_t gsmSMSByIndex(gsmSMSMessage_t * msg, uint8_t index) { char c; uint8_t i; char buff[13]; char *text; // SMS indexes are 1..10 if (!index || index>10) return 0; // Get the SMS message by the specified index sprintf(buff, "AT+CMGR=%d", index); _gsmWriteLine(buff); // Example responce: // +CMGR: "REC READ","+393357963938","","10/12/14,22:59:15+04"<0D><0A> // $NUM+393473153808$NUM+3355763944$RES$MSG:PiazzaleLargo e Lungo, Milano, Italy$12345<0D> // <0D><0A> // <0D><0A> // 0<0D> //***** Reading message Type, record format: // +CMGR: <TYPE> // wherem TYPE is: // Type Bytes Description // "REC UNREAD" 12 Received unread messages // "REC READ" 10 Received read messages // "STO UNSENT" 12 Stored unsent messages // "STO SENT" 10 Stored sent messages // Minimum unique substring: 6 Bytes // Thus, to parse the actual type, we read: // "+CMGR: " + 6Bytes = 13Bytes // Check if this message index is empty // In this case it is returned just "0<0D>" c = kfile_getc(&(gsm->fd)); if (c == EOF) goto parse_error; if (c == '0') { msg->from[0] = 0; msg->time[0] = 0; msg->text[0] = 0; LOG_INFO("SMS, P: %d, EMPTY\n", index); return 0; } // Read the rest of the initial record identifier if (!kfile_read(&(gsm->fd), buff, 12)) goto parse_error; // TODO: Parse message type // //***** Sender number // Scanning for second '"', than parse the sender number for (i=2; i; ) { c = kfile_getc(&(gsm->fd)); if (c == EOF) goto parse_error; if (c=='"') i--; } // Save the sender number, till next '"' for (i=0; i<15; i++) { c = kfile_getc(&(gsm->fd)); if (c == EOF) goto parse_error; if (c=='"') break; msg->from[i] = c; } msg->from[i] = '\0'; //***** Timestamp parsing // Scanning for three '"', than parse the timestamp for (i=3; i; ) { c = kfile_getc(&(gsm->fd)); if (c == EOF) goto parse_error; if (c=='"') i--; } // Save the timestamp (20 Bytes + terminator) if (!kfile_read(&(gsm->fd), msg->time, 20)) goto parse_error; msg->time[20] = '\0'; // Discard remaining chars till line termination ["<0D><0A>] if (!kfile_read(&(gsm->fd), buff, 3)) goto parse_error; //***** Message parsing text = msg->text; (*text) = kfile_getc(&(gsm->fd)); if ((*text) == EOF) goto parse_error; if ((*text) == '$') { // Scanning for first ':', than parse the message for (i=0; i<64; i++) { c = kfile_getc(&(gsm->fd)); if (c == EOF) goto parse_error; if (c==':') break; } // Save the message if (_gsmRead(text, 160) == -1) goto parse_error; } else { // We are already at the beginning of the message, // save the remainder of the text if (_gsmRead(text+1, 159) == -1) goto parse_error; } LOG_INFO("SMS, P: %d, T: %s, N: %s, M: %s\n", index, msg->time, msg->from, msg->text); return 1; parse_error: gsmDebug("Parse FAILED\n"); return -1; }