/** * Read \a _buf lenght \a size byte from serial flash memmory. * * For read in serial flash memory we * enble cs pin and send one byte of read opcode, * and then 3 byte of address of memory cell we * want to read. After the last byte of address we * can read data from so pin. * * \return the number of bytes read. */ static size_t flash25_read(struct KFile *_fd, void *buf, size_t size) { uint8_t *data = (uint8_t *)buf; Flash25 *fd = FLASH25_CAST(_fd); ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size); size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); //kprintf("Reading at addr[%lu], size[%d]\n", fd->seek_pos, size); SS_ACTIVE(); kfile_putc(FLASH25_READ, fd->channel); /* * Address that we want to read. */ kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel); kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel); kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel); kfile_read(fd->channel, data, size); SS_INACTIVE(); fd->fd.seek_pos += size; return size; }
/** * Send a character over pocketBus channel stream, handling escape mode. */ void pocketbus_putchar(struct PocketBusCtx *ctx, uint8_t c) { /* Update checksum */ rotating_update1(c, &ctx->out_cks); /* Escape characters with special meaning */ if (c == POCKETBUS_ESC || c == POCKETBUS_STX || c == POCKETBUS_ETX) kfile_putc(POCKETBUS_ESC, ctx->fd); kfile_putc(c, ctx->fd); }
/** * 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; }
void print_graph (KFile *stream, uint8_t type, uint8_t style) { MEDIAN *mArray; uint8_t i, j, index; int16_t highest, lowest, scale, value; static uint8_t last_type = 99, last_style = 99; char buf[21]; switch(type) { case MINGRAPH: mArray = &PowerMins; strncpy(buf, "Hourly", 7); break; case HOURGRAPH: mArray = &PowerHours; strncpy(buf, "Daily", 6); break; case DAYGRAPH: mArray = &PowerDays; strncpy(buf, "Monthly", 8); break; default: mArray = &PowerMins; break; } median_getHighest(mArray, &highest); median_getLowest(mArray, &lowest); scale = MAX(abs(highest), abs(lowest)); if ((last_type != type) || (last_style != style)) { kfile_putc(TERM_CLR, stream); last_type = type; last_style = style; } if ((style == GRAPHSTYLE) && scale) { for (i = 0; i < 4; i++) // for each line to be displayed { index = median_getStart(mArray); for (j = 0; j < median_getCount(mArray); j++) { median_getNext(mArray, &index, &value); buf[j] = graphmap[i][(int32_t)(value + scale) * 8 / scale]; } buf[j] = 0; kfile_printf(stream, "%c%c%c%s", TERM_CPC, TERM_ROW + i, TERM_COL, buf); } } else { kfile_printf(stream, "\r\n%s Range:\r\n %d to %d", buf, lowest, highest); } }
/** * Send a single command to serial flash memory. */ static void flash25_sendCmd(Flash25 *fd, Flash25Opcode cmd) { SS_ACTIVE(); kfile_putc(cmd, fd->channel); SS_INACTIVE(); }
static void tlv5618_write(Tlv5618 *ctx, uint16_t val) { TLV5618_CSLOW(ctx->cs_pin); kfile_putc(val >> 8, ctx->ch); kfile_putc(val & 0xFF, ctx->ch); kfile_flush(ctx->ch); TLV5618_CSHIGH(ctx->cs_pin); }
/** * Send pocketBus packet tail. */ void pocketbus_end(struct PocketBusCtx *ctx) { /* Send checksum */ rotating_t cks = cpu_to_be16(ctx->out_cks); pocketbus_write(ctx, &cks, sizeof(cks)); /* Send ETX */ kfile_putc(POCKETBUS_ETX, ctx->fd); }
// This is a callback we register with the protocol, // so we can process each packet as they are decoded. // Right now it just prints the packet to the serial port. static void mp1Callback(struct MP1Packet *packet) { if (SERIAL_DEBUG) { kfile_printf(&ser.fd, "%.*s\n", packet->dataLength, packet->data); } else { for (unsigned long i = 0; i < packet->dataLength; i++) { kfile_putc(packet->data[i], &ser.fd); } } }
/** * Write a string to kfile \a fd. * \return 0 if OK, EOF in case of error. */ int kfile_print(struct KFile *fd, const char *s) { while (*s) { if (kfile_putc(*s++, fd) == EOF) return EOF; } return 0; }
/** * Sector erase function. * * Erase a select \p sector of serial flash memory. * * \note A sector size is FLASH25_SECTOR_SIZE. * This operation could take a while. */ void flash25_sectorErase(Flash25 *fd, Flash25Sector sector) { /* * Erase a sector could take a while, * for debug we measure that time * see datasheet to compare this time. */ DB(ticks_t start_time = timer_clock()); SS_ACTIVE(); /* * To erase a sector of serial flash memory we must first * enable write with a WREN opcode command, before * the SECTOR_ERASE opcode. Sector is automatically * determinate if any address within the sector * is selected. */ kfile_putc(FLASH25_WREN, fd->channel); kfile_putc(FLASH25_SECTORE_ERASE,fd-> channel); /* * Address inside the sector that we want to * erase. */ kfile_putc(sector, fd->channel); SS_INACTIVE(); /* * We check serial flash memory state, and wait until ready-flag * is hight. */ flash25_waitReady(fd); DB(kprintf("Erased sector [%ld] in %ld ms\n", (unsigned long)sector, (unsigned long)ticks_to_ms(timer_clock() - start_time))); }
/** * Send pocketBus packet header. */ void pocketbus_begin(struct PocketBusCtx *ctx, pocketbus_addr_t addr) { PocketBusHdr hdr; hdr.ver = POCKETBUS_VER; hdr.addr = cpu_to_be16(addr); rotating_init(&ctx->out_cks); /* Send STX */ kfile_putc(POCKETBUS_STX, ctx->fd); /* Send header */ pocketbus_write(ctx, &hdr, sizeof(hdr)); }
/** * 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(); } }
static int8_t _gsmWrite(const char *cmd, size_t count) { size_t i; // NOTE: debugging should no be mixed to modem command and response to // avoid timeing issues and discrepancy between debug and release // versions gsmDebug("TX [%s]\n", cmd); // Purge any buffered data before sending a new command ser_purge(gsm); // Clear error flags ser_setstatus(gsm, 0); // Sending the AT command WATCHDOG_RESET(); for (i=0; cmd[i]!='\0' && count; i++, count--) { kfile_putc(cmd[i], &(gsm->fd)); WATCHDOG_RESET(); } return i; }
static void NORETURN hadarp_process(void) { char buf[16]; while (1) { if (sig_check(SIG_POLIFEMO)) kfile_putc('@', &ser.fd); if (kfile_gets(&ser.fd, buf, sizeof(buf)) == EOF) { hadarp_cnt = -1; kfile_clearerr(&ser.fd); continue; } if (buf[0] == '\0') { /* Discard empty strings */ continue; } char *endptr = buf; int hadarp_raw = strtol(buf, &endptr, 10); if (*endptr != '\0' || hadarp_raw > 10000 || hadarp_raw < 0) hadarp_cnt = -1; else { /* Compensate for geiger tube dead time */ float cps = hadarp_raw / 60.0; hadarp_cnt = ABS(cps / (1.0 - (cps * 1.9e-4)) * 60.0 + 0.5); } LOG_INFO("HADARP cnt:%d\n", hadarp_cnt); } }
/** * Write \a _buf in serial flash memory * * Before to write data into flash we must enable * memory writing. To do this we send a WRE command opcode. * After this command the flash is ready to be write, and so * we send a PROGRAM opcode followed to 3 byte of * address memory, at the end of last address byte * we can send the data. * When we finish to send all data, we disable cs * and flash write received data bytes on its memory. * * \note: WARNING: you could write only on erased memory section! * Each write time you could write max a memory page size, * because if you write more than memory page size the * address roll over to first byte of page. * * \return the number of bytes write. */ static size_t flash25_write(struct KFile *_fd, const void *_buf, size_t size) { flash25Offset_t offset; flash25Size_t total_write = 0; flash25Size_t wr_len; const uint8_t *data = (const uint8_t *) _buf; Flash25 *fd = FLASH25_CAST(_fd); ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size); size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos); while (size) { offset = fd->fd.seek_pos % (flash25Size_t)FLASH25_PAGE_SIZE; wr_len = MIN((flash25Size_t)size, FLASH25_PAGE_SIZE - (flash25Size_t)offset); kprintf("[seek_pos-<%lu>, offset-<%d>]\n", fd->fd.seek_pos, offset); /* * We check serial flash memory state, and wait until ready-flag * is high. */ flash25_waitReady(fd); /* * Start write cycle. * We could write only data not more long than one * page size. * * To write on serial flash memory we must first * enable write with a WREN opcode command, before * the PROGRAM opcode. * * \note: the same byte cannot be reprogrammed without * erasing the whole sector first. */ flash25_sendCmd(fd, FLASH25_WREN); SS_ACTIVE(); kfile_putc(FLASH25_PROGRAM, fd->channel); /* * Address that we want to write. */ kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel); kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel); kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel); kfile_write(fd->channel, data, wr_len); SS_INACTIVE(); data += wr_len; fd->fd.seek_pos += wr_len; size -= wr_len; total_write += wr_len; } kprintf("written %lu bytes\n", total_write); return total_write; }
int main(void){ init(); while (1){ /* * This function will look for new messages from the AFSK channel. * It will call the message_callback() function when a new message is received. * If there's nothing to do, this function will call cpu_relax() */ ax25_poll(&g_ax25); check_run_mode(); switch(currentMode){ case MODE_CFG: #if MOD_CONSOLE console_poll(); #endif #if MOD_BEACON beacon_broadcast_poll(); #endif break; #if MOD_TRACKER case MODE_TRACKER: tracker_poll(); break; #endif #if MOD_KISS case MODE_KISS:{ kiss_poll(); break; } #endif #if MOD_DIGI case MODE_DIGI:{ console_poll(); beacon_broadcast_poll(); break; } #endif default: break; }// end of switch(runMode) #if DEBUG_FREE_RAM { static ticks_t ts = 0; if(timer_clock_unlocked() - ts > ms_to_ticks(5000)){ ts = timer_clock_unlocked(); uint16_t ram = freeRam(); SERIAL_PRINTF((&g_serial),"%u\r\n",ram); } } #endif #if DEBUG_SOFT_SER // Dump the isr changes { SoftSerial *softSer = radioPort; static uint32_t i = 0; //static uint32_t j = 0; if(i++ == 30000){ i = 0; char c; while(softser_avail(softSer)){ c = softser_read(softSer); kfile_putc(c,&(g_serial.fd)); } char buf[8]; sprintf_P(buf,PSTR("0K\n\r")); softser_print(softSer,buf); } } #endif } // end of while(1) return 0; }
/** * \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); }