mirror of
https://github.com/m5stack/M5Stack_MicroPython.git
synced 2026-05-20 10:14:44 -07:00
'Ctrl+D' on empty line now performs full ESP32 soft reset 'math' module updated, added 'factorial' method 'uos' module updated, added 'mpycore' method to show MicroPython core git commit hash and date
792 lines
22 KiB
C
792 lines
22 KiB
C
/*
|
|
* This file is part of the MicroPython ESP32 project, https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2018 LoBo (https://github.com/loboris)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* MicroPython-ESP32 YModem driver/Module
|
|
*
|
|
* Copyright (C) 2017 Boris Lovosevic (https://github.com/loboris)
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "py/runtime.h"
|
|
#include "py/mperrno.h"
|
|
#include "sdkconfig.h"
|
|
|
|
#if CONFIG_MICROPY_RX_BUFFER_SIZE > 1079
|
|
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/semphr.h"
|
|
#include "rom/crc.h"
|
|
#include "uart.h"
|
|
#include "modymodem.h"
|
|
#include "py/ringbuf.h"
|
|
#include "mphalport.h"
|
|
#include "rom/uart.h"
|
|
|
|
#include <fcntl.h>
|
|
#include "extmod/vfs_native.h"
|
|
|
|
#ifdef CONFIG_MICROPY_USE_TELNET
|
|
#include "telnet.h"
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------
|
|
static unsigned short crc16(const unsigned char *buf, unsigned long count)
|
|
{
|
|
unsigned short crc = 0;
|
|
int i;
|
|
|
|
while(count--) {
|
|
crc = crc ^ *buf++ << 8;
|
|
|
|
for (i=0; i<8; i++) {
|
|
if (crc & 0x8000) crc = crc << 1 ^ 0x1021;
|
|
else crc = crc << 1;
|
|
}
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
/*
|
|
//---------------------------------------------------------------------------
|
|
static int32_t receive_Bytes (unsigned char *buf, int size, uint32_t timeout)
|
|
{
|
|
unsigned char ch;
|
|
int cb = -1;
|
|
int recv = 0;
|
|
|
|
while (recv < size) {
|
|
cb = mp_hal_stdin_rx_chr(timeout);
|
|
if (cb < 0) break;
|
|
buf[recv++] = (uint8_t)cb;
|
|
}
|
|
if (recv == 0) return -1;
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
//--------------------------------------------------------------
|
|
static int32_t Receive_Byte (unsigned char *c, uint32_t timeout)
|
|
{
|
|
int cb = mp_hal_stdin_rx_chr(timeout);
|
|
|
|
if (cb < 0) return -1;
|
|
*c = (uint8_t)cb;
|
|
return 0;
|
|
}
|
|
|
|
//------------------------
|
|
static void uart_consume()
|
|
{
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 1;
|
|
xSemaphoreGive(uart0_mutex);
|
|
int cb = mp_hal_stdin_rx_chr(1);
|
|
while (cb >= 0) {
|
|
cb = mp_hal_stdin_rx_chr(1);
|
|
}
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 0;
|
|
xSemaphoreGive(uart0_mutex);
|
|
}
|
|
|
|
//----------------------------------------
|
|
static void send_Bytes(char *buf, int len)
|
|
{
|
|
while (len--) {
|
|
uart_tx_one_char(*buf++);
|
|
}
|
|
}
|
|
//--------------------------------
|
|
static uint32_t Send_Byte (char c)
|
|
{
|
|
send_Bytes(&c,1);
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------
|
|
static void send_CA ( void ) {
|
|
Send_Byte(CA);
|
|
Send_Byte(CA);
|
|
}
|
|
|
|
//-----------------------------
|
|
static void send_ACK ( void ) {
|
|
Send_Byte(ACK);
|
|
}
|
|
|
|
//----------------------------------
|
|
static void send_ACKCRC16 ( void ) {
|
|
Send_Byte(ACK);
|
|
Send_Byte(CRC16);
|
|
}
|
|
|
|
//-----------------------------
|
|
static void send_NAK ( void ) {
|
|
Send_Byte(NAK);
|
|
}
|
|
|
|
//-------------------------------
|
|
static void send_CRC16 ( void ) {
|
|
Send_Byte(CRC16);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Receive a packet from sender
|
|
* @param data
|
|
* @param timeout
|
|
* @param length
|
|
* >0: packet length
|
|
* 0: end of transmission
|
|
* -1: abort by sender
|
|
* -2: error or crc error
|
|
* @retval 0: normally return
|
|
* -1: timeout
|
|
* -2: abort by user
|
|
*/
|
|
//--------------------------------------------------------------------------
|
|
static int32_t Receive_Packet (uint8_t *data, int *length, uint32_t timeout)
|
|
{
|
|
int count, packet_size, i;
|
|
unsigned char ch;
|
|
*length = 0;
|
|
|
|
// receive 1st byte
|
|
if (Receive_Byte(&ch, timeout) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
switch (ch) {
|
|
case SOH:
|
|
packet_size = PACKET_SIZE;
|
|
break;
|
|
case STX:
|
|
packet_size = PACKET_1K_SIZE;
|
|
break;
|
|
case EOT:
|
|
*length = 0;
|
|
return 0;
|
|
case CA:
|
|
if (Receive_Byte(&ch, timeout) < 0) {
|
|
return -2;
|
|
}
|
|
if (ch == CA) {
|
|
*length = -1;
|
|
return 0;
|
|
}
|
|
else return -1;
|
|
case ABORT1:
|
|
case ABORT2:
|
|
return -2;
|
|
default:
|
|
vTaskDelay(100 / portTICK_RATE_MS);
|
|
uart_consume();
|
|
return -1;
|
|
}
|
|
|
|
*data = (uint8_t)ch;
|
|
uint8_t *dptr = data+1;
|
|
count = packet_size + PACKET_OVERHEAD-1;
|
|
|
|
for (i=0; i<count; i++) {
|
|
if (Receive_Byte(&ch, timeout) < 0) {
|
|
return -1;
|
|
}
|
|
*dptr++ = (uint8_t)ch;;
|
|
}
|
|
|
|
if (data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff)) {
|
|
*length = -2;
|
|
return 0;
|
|
}
|
|
if (crc16(&data[PACKET_HEADER], packet_size + PACKET_TRAILER) != 0) {
|
|
*length = -2;
|
|
return 0;
|
|
}
|
|
|
|
*length = packet_size;
|
|
return 0;
|
|
}
|
|
|
|
// Receive a file using the ymodem protocol.
|
|
//-------------------------------------------------------------------------------
|
|
int Ymodem_Receive (FILE *ffd, unsigned int maxsize, char* getname, char *errmsg)
|
|
{
|
|
uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
|
|
uint8_t *file_ptr;
|
|
char file_size[128];
|
|
unsigned int i, file_len, write_len, session_done, file_done, packets_received, errors, size = 0;
|
|
int packet_length = 0;
|
|
file_len = 0;
|
|
int eof_cnt = 0;
|
|
|
|
for (session_done = 0, errors = 0; ;) {
|
|
for (packets_received = 0, file_done = 0; ;) {
|
|
switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT)) {
|
|
case 0: // normal return
|
|
switch (packet_length) {
|
|
case -1:
|
|
// Abort by sender
|
|
send_ACK();
|
|
size = -1;
|
|
sprintf(errmsg, "Abort by sender");
|
|
goto exit;
|
|
case -2:
|
|
// error
|
|
errors ++;
|
|
if (errors > 5) {
|
|
send_CA();
|
|
size = -2;
|
|
sprintf(errmsg, "Error limit exceeded");
|
|
goto exit;
|
|
}
|
|
send_NAK();
|
|
break;
|
|
case 0:
|
|
// End of transmission
|
|
eof_cnt++;
|
|
if (eof_cnt == 1) {
|
|
send_NAK();
|
|
}
|
|
else {
|
|
send_ACKCRC16();
|
|
}
|
|
break;
|
|
default:
|
|
// ** Normal packet **
|
|
if (eof_cnt > 1) {
|
|
send_ACK();
|
|
}
|
|
else if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0x000000ff)) {
|
|
errors ++;
|
|
if (errors > 5) {
|
|
send_CA();
|
|
size = -3;
|
|
sprintf(errmsg, "Wrong packet type received");
|
|
goto exit;
|
|
}
|
|
send_NAK();
|
|
}
|
|
else {
|
|
if (packets_received == 0) {
|
|
// ** First packet, Filename packet **
|
|
if (packet_data[PACKET_HEADER] != 0) {
|
|
errors = 0;
|
|
// ** Filename packet has valid data
|
|
if (getname) {
|
|
for (i = 0, file_ptr = packet_data + PACKET_HEADER; ((*file_ptr != 0) && (i < 64));) {
|
|
*getname = *file_ptr++;
|
|
getname++;
|
|
}
|
|
*getname = '\0';
|
|
}
|
|
for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < packet_length);) {
|
|
file_ptr++;
|
|
}
|
|
for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);) {
|
|
file_size[i++] = *file_ptr++;
|
|
}
|
|
file_size[i++] = '\0';
|
|
if (strlen(file_size) > 0) size = strtol(file_size, NULL, 10);
|
|
else size = 0;
|
|
|
|
// Test the size of the file
|
|
if ((size < 1) || (size > maxsize)) {
|
|
// End session
|
|
send_CA();
|
|
if (size > maxsize) size = -9;
|
|
else size = -4;
|
|
sprintf(errmsg, "Wrong file size");
|
|
goto exit;
|
|
}
|
|
|
|
file_len = 0;
|
|
send_ACKCRC16();
|
|
}
|
|
// Filename packet is empty, end session
|
|
else {
|
|
errors ++;
|
|
if (errors > 5) {
|
|
send_CA();
|
|
sprintf(errmsg, "Filename packet is empty, end session");
|
|
size = -5;
|
|
goto exit;
|
|
}
|
|
send_NAK();
|
|
}
|
|
}
|
|
else {
|
|
// ** Data packet **
|
|
// Write received data to file
|
|
if (file_len < size) {
|
|
file_len += packet_length; // total bytes received
|
|
if (file_len > size) {
|
|
write_len = packet_length - (file_len - size);
|
|
file_len = size;
|
|
}
|
|
else write_len = packet_length;
|
|
|
|
int written_bytes = fwrite((char*)(packet_data + PACKET_HEADER), 1, write_len, ffd);
|
|
if (written_bytes != write_len) { //failed
|
|
/* End session */
|
|
send_CA();
|
|
size = -6;
|
|
sprintf(errmsg, "fwrite() error [%d <> %d]", written_bytes, write_len);
|
|
goto exit;
|
|
}
|
|
}
|
|
//success
|
|
errors = 0;
|
|
send_ACK();
|
|
}
|
|
packets_received++;
|
|
}
|
|
}
|
|
break;
|
|
case -2: // user abort
|
|
send_CA();
|
|
size = -7;
|
|
sprintf(errmsg, "User abort");
|
|
goto exit;
|
|
default: // timeout
|
|
if (eof_cnt > 1) {
|
|
file_done = 1;
|
|
}
|
|
else {
|
|
errors ++;
|
|
if (errors > MAX_ERRORS) {
|
|
send_CA();
|
|
size = -8;
|
|
sprintf(errmsg, "Max errors");
|
|
goto exit;
|
|
}
|
|
send_CRC16();
|
|
}
|
|
}
|
|
if (file_done != 0) {
|
|
session_done = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (session_done != 0) break;
|
|
}
|
|
|
|
exit:
|
|
return size;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------
|
|
static void Ymodem_PrepareIntialPacket(uint8_t *data, char *fileName, uint32_t length)
|
|
{
|
|
uint16_t tempCRC;
|
|
|
|
memset(data, 0, PACKET_SIZE + PACKET_HEADER);
|
|
// Make first three packet
|
|
data[0] = SOH;
|
|
data[1] = 0x00;
|
|
data[2] = 0xff;
|
|
|
|
// add filename
|
|
sprintf((char *)(data+PACKET_HEADER), "%s", fileName);
|
|
|
|
//add file site
|
|
sprintf((char *)(data + PACKET_HEADER + strlen((char *)(data+PACKET_HEADER)) + 1), "%d", length);
|
|
data[PACKET_HEADER + strlen((char *)(data+PACKET_HEADER)) +
|
|
1 + strlen((char *)(data + PACKET_HEADER + strlen((char *)(data+PACKET_HEADER)) + 1))] = ' ';
|
|
|
|
// add crc
|
|
tempCRC = crc16(&data[PACKET_HEADER], PACKET_SIZE);
|
|
data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8;
|
|
data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
static void Ymodem_PrepareLastPacket(uint8_t *data)
|
|
{
|
|
uint16_t tempCRC;
|
|
|
|
memset(data, 0, PACKET_SIZE + PACKET_HEADER);
|
|
data[0] = SOH;
|
|
data[1] = 0x00;
|
|
data[2] = 0xff;
|
|
tempCRC = crc16(&data[PACKET_HEADER], PACKET_SIZE);
|
|
//tempCRC = crc16_le(0, &data[PACKET_HEADER], PACKET_SIZE);
|
|
data[PACKET_SIZE + PACKET_HEADER] = tempCRC >> 8;
|
|
data[PACKET_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
static void Ymodem_PreparePacket(uint8_t *data, uint8_t pktNo, uint32_t sizeBlk, FILE *ffd)
|
|
{
|
|
uint16_t i, size;
|
|
uint16_t tempCRC;
|
|
|
|
data[0] = STX;
|
|
data[1] = (pktNo & 0x000000ff);
|
|
data[2] = (~(pktNo & 0x000000ff));
|
|
|
|
size = sizeBlk < PACKET_1K_SIZE ? sizeBlk :PACKET_1K_SIZE;
|
|
// Read block from file
|
|
if (size > 0) {
|
|
size = fread(data + PACKET_HEADER, 1, size, ffd);
|
|
}
|
|
|
|
if ( size < PACKET_1K_SIZE) {
|
|
for (i = size + PACKET_HEADER; i < PACKET_1K_SIZE + PACKET_HEADER; i++) {
|
|
data[i] = 0x00; // EOF (0x1A) or 0x00
|
|
}
|
|
}
|
|
tempCRC = crc16(&data[PACKET_HEADER], PACKET_1K_SIZE);
|
|
//tempCRC = crc16_le(0, &data[PACKET_HEADER], PACKET_1K_SIZE);
|
|
data[PACKET_1K_SIZE + PACKET_HEADER] = tempCRC >> 8;
|
|
data[PACKET_1K_SIZE + PACKET_HEADER + 1] = tempCRC & 0xFF;
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
static uint8_t Ymodem_WaitResponse(uint8_t ackchr, uint8_t tmo)
|
|
{
|
|
unsigned char receivedC;
|
|
uint32_t errors = 0;
|
|
|
|
do {
|
|
if (Receive_Byte(&receivedC, NAK_TIMEOUT) == 0) {
|
|
if (receivedC == ackchr) {
|
|
return 1;
|
|
}
|
|
else if (receivedC == CA) {
|
|
send_CA();
|
|
return 2; // CA received, Sender abort
|
|
}
|
|
else if (receivedC == NAK) {
|
|
return 3;
|
|
}
|
|
else {
|
|
return 4;
|
|
}
|
|
}
|
|
else {
|
|
errors++;
|
|
}
|
|
}while (errors < tmo);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
int Ymodem_Transmit (char* sendFileName, unsigned int sizeFile, FILE *ffd, char *err_msg)
|
|
{
|
|
uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD];
|
|
uint16_t blkNumber;
|
|
unsigned char receivedC;
|
|
int err;
|
|
uint32_t size = 0;
|
|
|
|
// Wait for response from receiver
|
|
err = 0;
|
|
do {
|
|
Send_Byte(CRC16);
|
|
} while (Receive_Byte(&receivedC, NAK_TIMEOUT) < 0 && err++ < 45);
|
|
|
|
if (err >= 45 || receivedC != CRC16) {
|
|
send_CA();
|
|
sprintf(err_msg, "No response from host");
|
|
return -1;
|
|
}
|
|
|
|
// === Prepare first block and send it =======================================
|
|
/* When the receiving program receives this block and successfully
|
|
* opened the output file, it shall acknowledge this block with an ACK
|
|
* character and then proceed with a normal YMODEM file transfer
|
|
* beginning with a "C" or NAK tranmsitted by the receiver.
|
|
*/
|
|
Ymodem_PrepareIntialPacket(packet_data, sendFileName, sizeFile);
|
|
do
|
|
{
|
|
// Send Packet
|
|
send_Bytes((char *)packet_data, PACKET_SIZE + PACKET_OVERHEAD);
|
|
|
|
// Wait for Ack
|
|
err = Ymodem_WaitResponse(ACK, 10);
|
|
if (err == 0 || err == 4) {
|
|
send_CA();
|
|
sprintf(err_msg, "No ACK from host");
|
|
return -2; // timeout or wrong response
|
|
}
|
|
else if (err == 2) {
|
|
sprintf(err_msg, "Host abort");
|
|
return 98; // abort
|
|
}
|
|
}while (err != 1);
|
|
|
|
// After initial block the receiver sends 'C' after ACK
|
|
if (Ymodem_WaitResponse(CRC16, 10) != 1) {
|
|
send_CA();
|
|
sprintf(err_msg, "No CRC after ACK");
|
|
return -3;
|
|
}
|
|
|
|
// === Send file blocks ======================================================
|
|
size = sizeFile;
|
|
blkNumber = 0x01;
|
|
|
|
// Resend packet if NAK for a count of 10 else end of communication
|
|
while (size)
|
|
{
|
|
// Prepare and send next packet
|
|
Ymodem_PreparePacket(packet_data, blkNumber, size, ffd);
|
|
do
|
|
{
|
|
send_Bytes((char *)packet_data, PACKET_1K_SIZE + PACKET_OVERHEAD);
|
|
|
|
// Wait for Ack
|
|
err = Ymodem_WaitResponse(ACK, 10);
|
|
if (err == 1) {
|
|
blkNumber++;
|
|
if (size > PACKET_1K_SIZE) size -= PACKET_1K_SIZE; // Next packet
|
|
else size = 0; // Last packet sent
|
|
}
|
|
else if (err == 0 || err == 4) {
|
|
send_CA();
|
|
sprintf(err_msg, "Timeout or wrong response");
|
|
return -4; // timeout or wrong response
|
|
}
|
|
else if (err == 2) {
|
|
sprintf(err_msg, "Host abort");
|
|
return -5; // abort
|
|
}
|
|
}while(err != 1);
|
|
}
|
|
|
|
// === Send EOT ==============================================================
|
|
Send_Byte(EOT); // Send (EOT)
|
|
// Wait for Ack
|
|
do
|
|
{
|
|
// Wait for Ack
|
|
err = Ymodem_WaitResponse(ACK, 10);
|
|
if (err == 3) { // NAK
|
|
Send_Byte(EOT); // Send (EOT)
|
|
}
|
|
else if (err == 0 || err == 4) {
|
|
send_CA();
|
|
sprintf(err_msg, "Timeout or wrong response on EOF");
|
|
return -6; // timeout or wrong response
|
|
}
|
|
else if (err == 2) {
|
|
sprintf(err_msg, "Host abort on EOT");
|
|
return -7; // abort
|
|
}
|
|
}while (err != 1);
|
|
|
|
// === Receiver requests next file, prepare and send last packet =============
|
|
if (Ymodem_WaitResponse(CRC16, 10) != 1) {
|
|
sprintf(err_msg, "No CRC after EOF");
|
|
send_CA();
|
|
return -8;
|
|
}
|
|
|
|
Ymodem_PrepareLastPacket(packet_data);
|
|
do
|
|
{
|
|
// Send Packet
|
|
send_Bytes((char *)packet_data, PACKET_SIZE + PACKET_OVERHEAD);
|
|
|
|
// Wait for Ack
|
|
err = Ymodem_WaitResponse(ACK, 10);
|
|
if (err == 0 || err == 4) {
|
|
send_CA();
|
|
sprintf(err_msg, "Timeout or wrong response on last packet");
|
|
return -9; // timeout or wrong response
|
|
}
|
|
else if (err == 2) {
|
|
sprintf(err_msg, "Host abort on last packet");
|
|
return -10; // abort
|
|
}
|
|
}while (err != 1);
|
|
|
|
return 0; // file transmitted successfully
|
|
}
|
|
|
|
#endif
|
|
|
|
// ===== Module methods ===============================================================================
|
|
|
|
//--------------------------------------------
|
|
STATIC mp_obj_t ymodem_recv(mp_obj_t fname_in)
|
|
{
|
|
#ifdef CONFIG_MICROPY_USE_TELNET
|
|
if (telnet_loggedin()) {
|
|
mp_printf(&mp_plat_print, "Cannot execute from Telnet session\n");
|
|
return mp_const_none;
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_MICROPY_RX_BUFFER_SIZE > 1079
|
|
if (CONFIG_MICROPY_RX_BUFFER_SIZE < 1080) {
|
|
mp_printf(&mp_plat_print, "Minimum stdio RX buffer size is 1080 bytes, please rebuild.\n");
|
|
return mp_const_none;
|
|
}
|
|
|
|
const char *fname = mp_obj_str_get_str(fname_in);
|
|
char fullname[128] = {'\0'};
|
|
int err = 1;
|
|
char err_msg[128] = {'\0'};
|
|
char orig_name[128] = {'\0'};
|
|
|
|
if (physicalPath(fname, fullname) != 0) {
|
|
sprintf(err_msg, "File name cannot be resolved");
|
|
goto exit;
|
|
}
|
|
|
|
// Open the file
|
|
FILE *ffd = fopen(fullname, "wb");
|
|
if (ffd) {
|
|
mp_printf(&mp_plat_print, "\nReceiving file, please start YModem transfer on host ...\n");
|
|
mp_printf(&mp_plat_print, "(Press \"a\" to abort)\n");
|
|
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 1;
|
|
xSemaphoreGive(uart0_mutex);
|
|
|
|
int rec_res = Ymodem_Receive(ffd, 1000000, orig_name, err_msg);
|
|
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 0;
|
|
xSemaphoreGive(uart0_mutex);
|
|
|
|
fclose(ffd);
|
|
mp_printf(&mp_plat_print, "\r\n");
|
|
|
|
if (rec_res > 0) {
|
|
err = 0;
|
|
mp_printf(&mp_plat_print, "File received, size=%d, original name: \"%s\"\n", rec_res, orig_name);
|
|
}
|
|
else remove(fullname);
|
|
}
|
|
else {
|
|
sprintf(err_msg, "Opening file \"%s\" for writing.", fname);
|
|
}
|
|
|
|
exit:
|
|
mp_printf(&mp_plat_print, "\n%s%s\n", ((err == 0) ? "" : "Error: "), err_msg);
|
|
return mp_const_none;
|
|
#else
|
|
mp_printf(&mp_plat_print, "Minimum stdin RX buffer size is 1080 bytes, please rebuild.\n");
|
|
return mp_const_none;
|
|
#endif
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(ymodem_recv_obj, ymodem_recv);
|
|
|
|
//--------------------------------------------
|
|
STATIC mp_obj_t ymodem_send(mp_obj_t fname_in)
|
|
{
|
|
#ifdef CONFIG_MICROPY_USE_TELNET
|
|
if (telnet_loggedin()) {
|
|
mp_printf(&mp_plat_print, "Cannot execute from Telnet session\n");
|
|
return mp_const_none;
|
|
}
|
|
#endif
|
|
|
|
#if CONFIG_MICROPY_RX_BUFFER_SIZE > 1079
|
|
const char *fname = mp_obj_str_get_str(fname_in);
|
|
int fsize = 0, err = 0;
|
|
char fullname[128] = {'\0'};
|
|
char err_msg[128] = {'\0'};
|
|
|
|
if (physicalPath(fname, fullname) != 0) {
|
|
sprintf(err_msg, "File name cannot be resolved");
|
|
goto exit;
|
|
}
|
|
|
|
// Get file size
|
|
struct stat buf;
|
|
int res = stat(fullname, &buf);
|
|
if (res < 0) {
|
|
sprintf(err_msg, "Get file size.");
|
|
goto exit;
|
|
}
|
|
fsize = buf.st_size;
|
|
|
|
// Open the file
|
|
FILE *ffd = fopen(fullname, "rb");
|
|
if (ffd) {
|
|
mp_printf(&mp_plat_print, "\nSending file, please start YModem receive on host ...\n");
|
|
mp_printf(&mp_plat_print, "(Press \"a\" to abort)\n");
|
|
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 1;
|
|
xSemaphoreGive(uart0_mutex);
|
|
|
|
int trans_res = Ymodem_Transmit((char *)fname, fsize, ffd, err_msg);
|
|
|
|
xSemaphoreTake(uart0_mutex, UART_SEMAPHORE_WAIT);
|
|
uart0_raw_input = 0;
|
|
xSemaphoreGive(uart0_mutex);
|
|
|
|
fclose(ffd);
|
|
mp_printf(&mp_plat_print, "\r\n");
|
|
if (trans_res == 0) {
|
|
err = 0;
|
|
sprintf(err_msg, "Transfer complete, %d bytes sent", fsize);
|
|
}
|
|
}
|
|
else sprintf(err_msg, "Opening file \"%s\" for reading.", fname);
|
|
|
|
exit:
|
|
mp_printf(&mp_plat_print, "\n%s%s\n", ((err == 0) ? "" : "Error: "), err_msg);
|
|
return mp_const_none;
|
|
#else
|
|
mp_printf(&mp_plat_print, "Minimum stdin RX buffer size is 1080 bytes, please rebuild.\n");
|
|
return mp_const_none;
|
|
#endif
|
|
}
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(ymodem_send_obj, ymodem_send);
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
STATIC const mp_rom_map_elem_t ymodem_module_globals_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ymodem) },
|
|
|
|
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&ymodem_send_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&ymodem_recv_obj) }
|
|
};
|
|
|
|
STATIC MP_DEFINE_CONST_DICT(ymodem_module_globals, ymodem_module_globals_table);
|
|
|
|
//----------------------------------------
|
|
const mp_obj_module_t mp_module_ymodem = {
|
|
.base = { &mp_type_module },
|
|
.globals = (mp_obj_dict_t*)&ymodem_module_globals,
|
|
};
|
|
|