"Device not configured" when trying "make program-serial"

I try to run

make all PARTICLE_SERIAL_DEV=/dev/tty.usbmodemfa141 PLATFORM=photon program-serial

The last lines of returned output are:

Entering serial programmer mode:
stty -f /dev/tty.usbmodemfa141 28800
sleep 1
Flashing using serial ymodem protocol:
sz -b -v --ymodem ../../../build/target/user-part/platform-6-m/user-part.bin > /dev/tty.usbmodemfa141 < /dev/tty.usbmodemfa141

some delay… and then

/bin/sh: /dev/tty.usbmodemfa141: Device not configured
make[1]: *** [program-serial] Error 1
make: *** [modules/photon/user-part] Error 2

This happens with my own firmware, but also when using a default “tinker” app.

The photon LED turns purple after the stty call, so it does go into “ymodem mode”, but remains solid purple until timeout.

I doing this in the “latest” branch on a mac with 10.9.5 with “lrzsz” installed.

Hi Matt @mdma,

In the repo, a couple of months ago you made a commit (#34ef99c):
“ymodem updates working on the photon (using a python script.)”

Would you care to share this python script? So far “make program-serial” does not seem to work, and I would love to see a working example of firmware updates through the ymodem protocol.

Any help would be appreciated, thanks.

Hi @nicodegunst!

Could you try program-dfu instead? That should hopefully give you a quick workaround for the issue, and I’ll try to look at this one when there’s time.

Ah, I see you want to test out the ymodem protocol. Here’s the python script I used:


import os
import sys
import serial


def printStdErr(s):
    print(s, file=stderr)

def asbyte(v):
    return chr(v & 0xFF)



class LightYModem:
    """
    Receive_Packet
    - first byte SOH/STX (for 128/1024 byte size packets)
    - EOT (end)
    - CA CA abort
    - ABORT1 or ABORT2 is abort

    Then 2 bytes for seq-no (although the sequence number isn't checked)

    Then the packet data

    Then CRC16?

    First packet sent is a filename packet:
    - zero-terminated filename
    - file size (ascii) followed by space?
    """

    soh = 1     # 128 byte blocks
    stx = 2     # 1K blocks
    eot = 4
    ack = 6
    nak = 0x15
    ca =  0x18          # 24
    crc16 = 0x43        # 67
    abort1 = 0x41       # 65
    abort2 = 0x61       # 97

    packet_len = 1024
    expected_packet_len = packet_len+5
    packet_mark = stx

    def __init__(self):
        self.seq = None
        self.ymodem = None

    def flush(self):
        pass
        #self.ymodem.flush()

    def blocking_read(self):
        ch = ''
        while not ch:
            ch = self.ymodem.read(1)
        printStdErr("read %d " % ord(ch))
        return ch

    def _read_response(self):
        ch1 = self.blocking_read()
        ch1 = ord(ch1)
        printStdErr("response %d" % (ch1))

        if ch1==LightYModem.ack and self.seq==0:    # may send also a crc16
            ch2 = self.blocking_read()
        elif ch1==LightYModem.ca:                   # cancel, always sent in pairs
            ch2 = self.blocking_read()
        return ch1

    def write(self, packet):
        for x in range(len(packet)):
            self.ymodem.write(packet[x])

        return len(packet);

    def _send_ymodem_packet(self, data):
        # pad string to 1024 chars
        data = data.ljust(LightYModem.packet_len)
        seqchr = asbyte(self.seq & 0xFF)
        seqchr_neg = asbyte((-self.seq-1) & 0xFF)
        crc16 = '\x00\x00'
        packet = asbyte(LightYModem.packet_mark) + seqchr + seqchr_neg + data + crc16
        if len(packet)!=LightYModem.expected_packet_len:
            raise Exception("packet length is wrong!")

        written = self.write(packet)
        printStdErr("sent packet data, flush..."+str(written))
        self.flush()
        printStdErr("wait response..")
        response = self._read_response()
        if response==LightYModem.ack:
            ("sent packet nr %d " % (self.seq))
            self.seq += 1
        return response

    def _send_close(self):
        self.ymodem.write(asbyte(LightYModem.eot))
        self.flush()
        response = self._read_response()
        if response == LightYModem.ack:
            self.send_filename_header("", 0)
            self.ymodem.close()

    def send_packet(self, file, output):
        response = LightYModem.eot
        data = file.read(LightYModem.packet_len)
        if len(data):
            response = self._send_ymodem_packet(data)
        return response

    def send_filename_header(self, name, size):
        self.seq = 0
        packet = name + asbyte(0) + str(size) + ' '
        return self._send_ymodem_packet(packet)

    def transfer(self, file, ymodem, output):
        self.ymodem = ymodem
        """
        file: the file to transfer via ymodem
        ymodem: the ymodem endpoint (a file-like object supporting write)
        output: a stream for output messages
        """

        file.seek(0, os.SEEK_END)
        size = file.tell()
        file.seek(0, os.SEEK_SET)
        response = self.send_filename_header("binary", size)
        while response==LightYModem.ack:
            response = self.send_packet(file, output)

        file.close()
        if response==LightYModem.eot:
            self._send_close()

        return response



def ymodem(args):
    port = args[1]
    filename = args[2]
    ser = serial.Serial(port, baudrate=28800)
    file = open(filename, 'rb')
    result = LightYModem().transfer(file, ser, sys.stderr)
    file.close()
    print("result: " + str(result))

    try:
        while (True):
            print(ser.read())
    except:
        pass
    print("Done")

if __name__ == '__main__':
    ymodem(sys.argv)

Usage:

ymodem.py  <serial-device> <filename>

Cheers :smile:
mat

Thanks a lot, just tested it, and it works!

Got one error (on OS-X):

File "./ymodem.py", line 7
    print("", *objs, file=stderr)
              ^
SyntaxError: invalid syntax

So I replaced it with ‘print("")’ (I don’t speak Python:p), and after installing pySerial, everything went fine.

The code looks pretty simple, my plan is to port it to Javascript, so it can be used with NodeJS. I’ll let you know how it goes.

Thanks again.

1 Like

Hi @mdma,
I just finished creating a JS version of the python script you provided, and created an NPM module of it.
With this module, it is possible to push firmware to the Photon using only nodejs, so no need to install dfu-util or lrzsz. This could be useful for other node-js based projects, like https://github.com/spark/particle-dev-app, https://github.com/spark/spark-dev and https://github.com/spark/particle-cli.
So just letting you guys know: @brycekahle, @suda, @nexxy

NPM: https://www.npmjs.com/package/particle-ymodem
Github: https://github.com/nicodegunst/particle-ymodem

2 Likes

Nice! I’ll check it out!

@nicodegunst, this is super cool! I’ve starred and watched the repo! I know we talked about supporting ymodem in the CLI, so this might be something we do in the future.

I will definitely be trying it out when I get a chance.

Thanks for pinging me about this! :smiley: