Shop OBEX P1 Docs P2 Docs Learn Events
Wanted: Xmodem upload (send) code — Parallax Forums

Wanted: Xmodem upload (send) code

Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
edited 2009-01-11 23:57 in Propeller 1
There are several projects which have incorporated Xmodem download code,
but I'm looking for Xmodem "send" to upload to another device.

Has anyone got code for this handy?

Thanks!
OBC

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
New to the Propeller?

Check out: Protoboard Introduction , Propeller Cookbook 1.4 & Software Index
Updates to the Cookbook are now posted to: Propeller.warrantyvoid.us
Got an SD card connected? - PropDOS

Comments

  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-01-11 06:36
    I don't have any spin code. This is vb.net code. (can I post that here?!)

    As an aside, wouldn't it be cool to be able to translate basic to spin? Even if it were one of the earlier/simpler versions of basic? Especially since a lot of vb.net is really an older version of basic repackaged eg
    Dim Input As New FileStream(Filenamepath, FileMode.Open, FileAccess.Read)
    is the same as
    Open "I",1,Filenamepath

    So it can be simplified. Maybe even simulated? Anyway, I digress. VB.net code below, and also a description of the protocol so it makes a bit more sense.

    Sub XModemSend(ByRef FName As String, ByVal TimerRestart As Boolean)
    Dim Filenamepath As String
    Dim j As Integer
    Dim k As Integer
    Dim LineOfText As String
    Dim SerialString As String
    Dim Counter As Integer
    Dim ErrorString As String
    Dim Packetnumber As Integer
    Dim Checksum As Long
    Dim OnesComplement As Byte
    Dim ByteRead As Byte
    Dim BinaryFileLength As Long
    Dim BinaryFileCounter As Long
    Dim Percent As Single
    Dim ErrorCounter As Byte ' 0 to 10
    Dim CPMFilename As String
    ' timer restart =true for sending via menu. False for auto send
    Filenamepath = FName
    Packetnumber = 1 ' 1 for the first packet (not zero)
    Try
    Dim Input As New FileStream(Filenamepath, FileMode.Open, FileAccess.Read)
    Dim br As New BinaryReader(Input)
    Label3.Text = "Error Count"
    Label2.Text = "0%"
    BinaryFileLength = br.BaseStream.Length() - 1
    'i = Len(Filepath) + 1 + 1 ' eg c:\n8vem and a \ = 9 and 1 more for start of name only
    Call Get_CPM_Filename(Filenamepath, CPMFilename)
    CPMFilename = Strings.UCase(CPMFilename)
    ' send a <CR> (in case some rubbish characters on the screen)
    LineOfText = Strings.Chr(13)
    Call StringToPacket(LineOfText)
    Sleep(300) ' 300 for 4800 to process the return
    ' erase the file in case it exists
    LineOfText = "ERA " + CPMFilename + vbCrLf
    Call StringToPacket(LineOfText)
    'LineOfText = vbCrLf
    'Call StringToPacket(LineOfText)
    Sleep(300) ' 1000 for 4800
    ' run xmodem on the board
    LineOfText = "XMODEM R " + CPMFilename + vbCrLf
    Call StringToPacket(LineOfText) '
    'LineOfText = vbCrLf
    'Call StringToPacket(LineOfText) ' send a return/LF
    Sleep(500) ' wait for text to come back before disabling timer
    ' 100 is a bit short, 300 works, 200 seems a bit better
    ' xmodem is taking 2 seconds to acknowledge so have at least this much time
    ' to get the text back
    If TimerRestart = False Then
    Call ClearInputBuffer() ' clear the buffer into the PC
    End If
    If TimerRestart = True Then Timer1.Enabled = False 'disable echo and all reads so can control them below
    ' if timerrestart=false then called from a program where it is already disabled
    ' now wait for the N8VEM to send a chr(21) - will still be echoing back the text for a bit
    Do
    SerialString = ""
    If SerialPort.BytesToRead > 0 Then
    SerialPort.Read(InPacket, 0, 1) ' get one byte
    SerialString = Chr(InPacket(0)) ' get a single character/string/byte
    End If
    If InPacket(0) = 21 Then
    ErrorString = "NAK"
    Exit Do ' got a ^U
    End If
    If SerialString <> "" Then
    'LineOfText = SerialString
    'Call TextLines(LineOfText) ' print it out unless it is a chr21
    End If
    Counter = Counter + 1
    Sleep(10) ' don't change this one - this is waiting for NAK
    Label1.Text = "Waiting for NAK to start" + Strings.Str(Counter * 10) + "ms" ' display in milliseconds
    System.Windows.Forms.Application.DoEvents() ' update the label1 message
    ' add a counter and timeout if nothing
    If Counter > 800 Then
    ErrorString = "Timeout"
    Exit Do
    End If
    If ErrorString <> "" Then Exit Do
    Loop
    Label1.Text = ErrorString
    ' bug with vb.net - strings don't go to 255 so have to send data as bytes
    Do
    ' act on each byte in the buffer array here
    Sleep(1) ' 60 for 4800 but 1 working for 38400
    'If Radio1200 = True Then Sleep(250)
    XOut(0) = 1 'SOH ^A
    XOut(1) = Packetnumber
    OnesComplement = 255 - Packetnumber
    XOut(2) = OnesComplement
    Packetnumber = Packetnumber + 1
    If Packetnumber > 255 Then Packetnumber = Packetnumber - 256
    Checksum = 0
    For i = 0 To 127 ' get 128 bytes from file
    If BinaryFileCounter <= BinaryFileLength Then
    ByteRead = br.ReadByte ' get a byte
    Else
    ByteRead = 26 ' pad with char 26 = hex 1A because hyperterm does this ? why but it works
    End If
    XOut(i + 3) = ByteRead
    Checksum = Checksum + ByteRead
    BinaryFileCounter = BinaryFileCounter + 1
    Next
    ' create checksum
    Do
    If Checksum < 256 Then Exit Do ' work out checksum
    Checksum = Checksum - 256
    Loop
    XOut(131) = Checksum
    Call OutputXout()
    System.Windows.Forms.Application.DoEvents() ' update the label
    Do
    k = 0
    Do
    Sleep(10) '80 for 4800 wait for the acknowledge which is a character 6 delay of 80 only occasionally loops so k>0
    j = SerialPort.BytesToRead
    If j >= 1 Then
    SerialPort.Read(InPacket, 0, 1) ' get one byte
    Exit Do
    End If
    k = k + 1
    If k > 70 Then
    InPacket(0) = 0 ' for below error testing
    Exit Do
    End If
    Loop
    If InPacket(0) = 6 Then Exit Do ' board got the packet
    If InPacket(0) = 21 Or InPacket(0) = 0 Then
    ' didn't get it so try sending again
    ErrorCounter = ErrorCounter + 1
    Call OutputXout()
    Label3.Text = "Error: " + Strings.Str(ErrorCounter)
    System.Windows.Forms.Application.DoEvents() ' update the label
    End If
    Label3.Text = "Error: " + Strings.Str(ErrorCounter)
    System.Windows.Forms.Application.DoEvents() ' update the label
    If ErrorCounter >= 10 Then Exit Do
    Loop
    If ErrorCounter >= 10 Then
    Label1.Text = "10 errors - aborting"
    Label2.Text = "0%"
    OutPacket(0) = 24 ' send a ^X cancel
    SerialPort.Write(OutPacket, 0, 1) ' send 1 byte
    OutPacket(0) = 3 ' send a ^C
    SerialPort.Write(OutPacket, 0, 1) ' send 1 byte
    Exit Do
    End If
    If BinaryFileCounter > BinaryFileLength Then Exit Do ' finish up
    Label1.Text = "Sent packet: " + Strings.Str(Packetnumber) + " = OK"
    Percent = BinaryFileCounter / BinaryFileLength
    Percent = Percent * 100
    Percent = Int(Percent)
    Label2.Text = Strings.Str(Percent) + "%"
    Loop
    If ErrorCounter < 10 Then
    Sleep(100)
    OutPacket(0) = 4
    SerialPort.Write(OutPacket, 0, 1) ' send 1 byte
    Label2.Text = "100%"
    Label1.Text = "Finished all OK"
    End If
    Input.Close()
    Sleep(200) ' wait for next file
    If TimerRestart = True Then Timer1.Enabled = True ' update the text - no sleeps after this
    System.Windows.Forms.Application.DoEvents() ' update the labels
    Catch ex As Exception
    Close()
    If TimerRestart = TimerRestart = True Then Timer1.Enabled = True ' update the text
    System.Windows.Forms.Application.DoEvents() ' update the labels
    MsgBox("No file found")
    End Try
    End Sub

    Perception presents:
    Understanding The X-Modem File Transfer Protocol

    by Em Decay

    This has to be one of the most internationally accepted protocols for upload-
    ing and downloading binary and text files. It is fairly straight-forward as
    to how it is set up and there are some error checking capablities.


    --- Before you begin ---

    Things you need to know beforehand...

    The following terms are simply ascii codes:
    SOH = chr(1) = CTRL-A =
    EOT = chr(4) = CTRL-D = End of Transmission
    ACK = chr(6) = CTRL-F = Positive Acknowledgement
    NAK = chr(21) = CTRL-U = Negative Acknowledgement
    CAN = chr(24) = CTRL-X = Cancel

    In order to send the file, you must first divide it into 128 byte sections
    (packets). Bytes 0-127 of the file make up the first packet, bytes 128-255
    make up the second packet, etc.

    The packet number sent is simply the number of the packet. If the packet
    number is greater than 255, then subtract 256 repeatly until the number is
    between 0 and 255. For example, if you were sending packet 731, then you
    would send 731 - 256 - 256 = 219.

    The 1's complement of a byte (to make life easy) is simply 255 minus the
    byte. For example, if you had to take the 1's complement of 142, the answer
    would be 255 - 142 = 133.

    The checksum is the value of all the bytes in the packet added together. For
    example, if the first five bytes were 45, 12, 64, 236, 173 and the other 123
    bytes were zeroes, the checksum would be 45+12+64+236+173+0+0+...+0 = 530.
    However, to make each block one byte smaller, they repeatly subtract 256
    from the checksum until it is between 0 and 255. In this case, the checksum
    would be 530 - 256 - 256 = 18.

    The first byte the downloader sends is referred to as the NCGbyte.

    Provided that you aren't lost already, here is what happens next. The steps
    below describe who sends what when [noparse]:)[/noparse]


    --- The Actual Transfer ---

    The uploader waits until the downloader sends a NAK byte. The NAK byte
    is the signal that the downloader is ready to start. This byte is referred
    to as the NCGbyte. If the downloader takes too long or an error occurs then
    the uploader will stop waiting or "Time Out". If this happens, then the
    file transfer must restart.

    With each packet sent...

    The uploader sends:

    1. an SOH byte {1 byte}
    2. the packet number {1 byte}
    3. the 1's complement of the packet number {1 byte}
    4. the packet {128 bytes}
    5. the checksum {1 byte}
    The above five things are called the block.

    The downloader:

    1. ensures that the packet number sent matches the actual packet number
    that it is (If the third block send has a '4' as the second byte,
    something is wrong --> CANCEL TRANSFER (send CAN byte))
    2. adds the packet number and the 1's complement of it together to make
    sure that they add up to 255. if they don't --> CANCEL TRANSFER
    3. adds up all the bytes in the packet together --> THE SUM
    4. compares the last two significant digits of THE SUM with the checksum
    5. if everything looks ok (sum=checksum), then the downloader appends the
    bytes in the packet to the file being created (sent). The down-
    loader then sends an ACK byte which tells the uploader to send the
    next block.
    if the sums do not match then the downloader sends an NAK byte which
    tells the uploader to send the same block it just sent over again.

    When the uploader sends an EOT byte instead of an SOH byte, the downloader
    sends a NAK byte. If the uploader sends another EOT immediately after that,
    the downloader sends an ACK byte and the transfer is complete.

    Another thing, the downloader can cancel the transfer at any time by sending
    a CAN byte. The uploader can only cancel between blocks by sending a CAN
    byte. It is recommended that you send anywhere between 2 and 8 consecutive
    CAN bytes when you wish to cancel as some programs will not let you abort if
    only 1 CAN byte is sent.


    --- Wrap Up ---

    Hopefully, you were able to follow along. [noparse]:)[/noparse] If not, you can e-mail me at
    em_decay@norlink.net and I will try to clarify it for you. Have fun [noparse]:)[/noparse]

    Perception: Em Decay -- Mark Korhonen
    Cmf
    Chris Fillion

    Written on Dec.28/95
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2009-01-11 06:41
    Ah, that is PERFECT!

    I believe I can translate that no problem.

    Thanks for posting it. Once I get both halves working, I'll create an object for this as it
    looks like this question is raised about twice a year. (searching: search.parallax.com)

    OBC

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    New to the Propeller?

    Check out: Protoboard Introduction , Propeller Cookbook 1.4 & Software Index
    Updates to the Cookbook are now posted to: Propeller.warrantyvoid.us
    Got an SD card connected? - PropDOS
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-01-11 06:52
    Maybe start with the description first and code from that, rather than start with the vb.net code? The code is complicated. The description is clear, and it may well lend itself to shorter code in spin anyway.
  • heaterheater Posts: 3,370
    edited 2009-01-11 08:09
    The wikipedia article on XMODEM indicates that CAN (cancel) was not used in XMODEM and goes on to explain that use of CAN and many other suggestions were rejected by the original author Ward Christensen. This resulting in a plethora of incompatible "improved" protocols.

    Searching around I find the original and proper XMODEM is described in chapter 7 of the attached document (by the author of YMODEM) and it states "the use of CAN was never adopted as a standard"

    Chapter 4 describes use of a double CAN as an enhancement other enhancements being 16 bit CRCs etc etc.

    Be ready for thousands of support calls as people try out XMODEM for the Prop with all kinds of incompatible software[noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2009-01-11 08:40
    See also this C source code cvs.sourceforge.jp/cgi-bin/viewcvs.cgi/ttssh2/teraterm/ttpfile/xmodem.c?view=markup

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2009-01-11 11:28
    Of course there is nothing like the original, attached. It's very well commented.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2009-01-11 23:57
    Thanks guys!

    Spent a couple hours (chickening out) trying to adapt Ray's Ymodem upload to work without success.
    Finally relented to writing it from scratch. (took about an hour)
    A primitive version has been added to my current project.

    OBC

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    New to the Propeller?

    Check out: Protoboard Introduction , Propeller Cookbook 1.4 & Software Index
    Updates to the Cookbook are now posted to: Propeller.warrantyvoid.us
    Got an SD card connected? - PropDOS

    Post Edited (Oldbitcollector) : 1/12/2009 12:45:46 AM GMT
Sign In or Register to comment.