Shop OBEX P1 Docs P2 Docs Learn Events
Need help reading file from VMusic2 - Page 2 — Parallax Forums

Need help reading file from VMusic2

24

Comments

  • VadooVadoo Posts: 92
    edited 2011-06-29 14:27
    Am I wrong in thinking I can take a stored byte containing $00 - $FF, read it one bit at a time, and get 00000000 - 11111111? Using each bit simply as a 1 or a 0, and use that 1 or 0 for something as simple as an OUTA[#]~~ or OUTA[#]~?
  • VadooVadoo Posts: 92
    edited 2011-06-29 14:34
     repeat 
        dataptr[index]:= UART.in
        debug.out(dataptr[index++])
    

    Is there any reason this would not work desirably?
    The thought is to store the data and send it to the pc terminal efficiently and fast enough so I don't miss pieces.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-06-29 17:06
    Hi Vadoo, the way I have done file reading in the past when the file was larger than my receive buffer was to read the file data in small packets.

    To do this with the Vmusic the first thing is to get the file size of the file you want to read.

    Assuming you are reading ten byte packets then Repeat count = file size / 10.

    You would also need another small routine to read a remainder if any ( which would be the modulus of filesize/10 )

    Having the above information your repeat loop reads ten bytes at a time, stores them, reads the next ten, appends them to the stored value etc etc

    To try and give a better picture of what I am talking about check the attached file which was written with the BS2 in mind ,Step 4 should not be to hard to follow.

    Jeff T.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-06-29 19:16
    One thing that may be confusing in the previous attachment is that everything is done with the shortened command set. To put that straight I have another attachment, a spin method using the extended command set, that will read the size of a file and display it to a debug terminal. The method is called Check_Size and will require the two serial objects (VMusic2 and Debug) configuring and starting by you. At the beginning of the method I set the input to IPH followed by a loop that waits for the prompt, you may not need to do this depending on your configuration. Replace the text "FILENAME" with the file you wish to check the size of. As your program grows using a seperate method or sub routine for each VMusic instruction will keep your main code manageable.

    As a side note I think you are doing the right thing by using the default 9600 baud while you put your program together, somewhere down the road you may feel the need for speed and increase your baud rate

    Jeff T.
  • VadooVadoo Posts: 92
    edited 2011-06-29 20:28
    I like the FileSize object. Thanks for the help Unsoundcode! It may be the weekend before I get to dive too deep into it, but i have some thoughts to try out. Can you please explain this part of the code. I mostly understand it, but not entirely confidently :) More the last two lines.
                    lowbyte:=VMusic2.rxtime(10)
              
                    highbyte:=VMusic2.rxtime(10)
                    
                    filesize:=highbyte << 8
                    filesize:= filesize|lowbyte
    

    Thanks!
  • VadooVadoo Posts: 92
    edited 2011-06-29 21:15
    I have success!!! Well a little. After playing with the settings of the Parallax Serial Terminal, I can sort see my file being read. Problem is, the file contains a series of 00 and FF. The serial terminal is showing a bunch of ÿ, which seem to represent the FF locations. Also its not showing the 00, it doesn't even show a space, just all of the FF as ÿ with no spaces. Now if I set it to clear screen on 0, I see the ÿ quickly flash and disappear, and they certainly seem to accurately represent the positions of the FFs. So that's good! Thoughts?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-06-29 21:36
    Vadoo,

    I often add a couple of methods to my programs to make sure the output is legitimate ASCII characters.
    PUB SafeBug(localPtr, localSize)
      repeat result from 0 to localSize - 1
        TbugTx(byte[localPtr + result])
     
    PRI TbugTx(localCharacter)
      if (localCharacter > 31 and localCharacter < 127) or localCharacter == 13
        Com.tx(_DebugCom, localCharacter)
      else
        Com.tx(_DebugCom, 60)
        Com.tx(_DebugCom, 36)
        TbugHex(localCharacter, 2)
        Com.tx(_DebugCom, 62)
     
    PRI TbugHex(localHex, localSize)
       Com.hex(_DebugCom, localHex, localSize)
    

    You'll need to change the syntax to match the serial object you're using.

    I call SafeBug with a pointer to the text I want to display and include the number of bytes to display since it isn't watching for a terminating zero like most string methods.

    Duane
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-06-30 07:34
    Vadoo, in answer to the file size instruction the VMusic returns a 32 bit long which is the value of the file size. The 32 bit long is divided into four bytes that are 8 bits long and it sends the lowest byte first. It is our job to put those bytes back into one single value when we receive them. One thing to note is that the way I coded it I am assuming the value of file size will always be below 65535 so I only need to grab the first 2 of the 4 bytes (lowbyte and highbyte). The first line you asked about shifts the highbyte 8 positions to the left in our filesize variable, the second line is a bitwise OR of filesize and lowbyte which combines highbyte and lowbyte into one single value . The 2 previous lines are just receive instructions with a time out of 10mS, I gave it the time out to make sure I did not skip the incoming data.
             lowbyte:=VMusic2.rxtime(10)
              
             highbyte:=VMusic2.rxtime(10)
                    
             filesize:=highbyte << 8
             filesize:= filesize|lowbyte
    

    Did you manage to get it to work for you, I got it to work but I have a tendency to do everything using the SCS so you will have to play around a little to get it working maybe. When you do we can look at the read loops required.

    Duane's point about checking for ASCII v receiving bytes as binary values between 0-255 is crucial in how you treat the data, are your files text files or binary files.

    Jeff T.
  • VadooVadoo Posts: 92
    edited 2011-06-30 13:49
    How about this part:
    repeat                          {Read and display}
           x:=VMusic2.rxcheck
          if x<> -1 
               
                if x== $20
    ....
    

    The if x == $20. What is it doing? I assume an input from the VMusic2, but I can't find anywhere that it says it sends any kind of initiator type signal. My understanding is it just starts sending data and a prompt when complete. Ill test it out this weekend, but I would think the if x== $20 is not needed, it could go straight to lowbyte highbyte? Though an initiating byte, or some sort of "Hey here comes your data" from the VMusic2 would be greatly helpfull, I just can't find it written anywhere!

    I guess a binary file? I didn't make the file so not sure. But I use WebHex to view it, and it just contains $00 - $FF. And a -d at the beginning.
  • VadooVadoo Posts: 92
    edited 2011-06-30 15:55
    CON
    
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000
    
    OBJ
      Debug: "PC_Debug"
      VMusic2: "UART_Debug"   
    
    PUB Check_Size |x, lowbyte, highbyte, filesize
    
    waitcnt(clkfreq * 6 + cnt)
    debug.start(9600)                     
    VMusic2.start(9600)
    
    x:=-1
    
    VMusic2.str(string("IPH",$0D))           {Set IPH}
    
    repeat                         {Wait for prompt}
           x:=VMusic2.in
          if x<> -1 
                Debug.out(x)
              if x==">"               
                 quit 
            x:=-1        
    
    VMusic2.str(string("DIR data.hlx",$0D))     {Send command to read filesize}
         
    repeat                          {Read and display}
           x:=VMusic2.in
          if x<> -1 
               
                if x== $20
                  
                    lowbyte:=VMusic2.in
              
                    highbyte:=VMusic2.in
                    
                    filesize:=highbyte << 8
                    filesize:= filesize|lowbyte
                    Debug.str(string("Filesize "))  
                    Debug.dec(filesize)
                    Debug.str(string(" bytes"))
                    
              if x==">"
                 Debug.out(13)    
                 quit 
            x:=-1
    
    Debug.str(string("DONE"))        
    repeat
    

    Works great.
    Not sure I understand how with the $20 part in there....
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-06-30 18:40
    Vadoo, this would be the data returned from the VMusic immediately after your instruction to read the file size :-

    "data.hlx" $20 <filesize byte 1> <filesize byte 2> <filesize byte 3> <filesize byte 4>

    so I know that once I have issued the filesize instruction all I have to do is wait for the first space character ( $20 ) and the next two bytes are the ones I want to grab, the order is always the same no matter what the filename.

    If there is no data to read in the serial buffer the value in the buffer will be -1, I only want to use data from the buffer when there is data to read, therefore if x is not equal to -1 ( x<> -1 ) there is data there I need to do something with.

    File size has a benefit not at first obvious, if the file size instruction does not return a value then you would know that the file does not exist or has been corrupted in some way. If the instruction fails it has no detrimental effect on your hardware providing you are aware of it and handle it accordingly. This is not true with many of the other VDAP instructions.

    Do you have a copy of the VDAP firmware, I think it's an important reference.

    I'm pleased you took the time to figure it out and get it working for yourself, I also hope the above clarified a few points for you.

    Jeff T.
  • VadooVadoo Posts: 92
    edited 2011-06-30 19:41
    Vadoo, this would be the data returned from the VMusic immediately after your instruction to read the file size :-

    "data.hlx" $20 <filesize byte 1> <filesize byte 2> <filesize byte 3> <filesize byte 4>

    so I know that once I have issued the filesize instruction all I have to do is wait for the first space character ( $20 ) and the next two bytes are the ones I want to grab, the order is always the same no matter what the filename.

    If there is no data to read in the serial buffer the value in the buffer will be -1, I only want to use data from the buffer when there is data to read, therefore if x is not equal to -1 ( x<> -1 ) there is data there I need to do something with.

    File size has a benefit not at first obvious, if the file size instruction does not return a value then you would know that the file does not exist or has been corrupted in some way. If the instruction fails it has no detrimental effect on your hardware providing you are aware of it and handle it accordingly. This is not true with many of the other VDAP instructions.

    Do you have a copy of the VDAP firmware, I think it's an important reference.

    I'm pleased you took the time to figure it out and get it working for yourself, I also hope the above clarified a few points for you.

    Jeff T.

    Yes greatly, thank you! As for the firmware, yes. I have been using it a lot.
    I'm still fighting with this data reading and storage problem though. Ultimately I need to read and store a decent amount of data. I'm aiming for a 512 buffer. That way I can do other things for a while before refilling the buffer. But everything I write either gives me jarbled information or my code is too long and I miss pieces of data because of it. Not to mention I still need to figure out how to use that buffer a bit at a time for the shift register...
    I am slowly making progress on storing the data though I think. I feel I'm close to figuring it out.... :/
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2011-07-01 16:41
    Vadoo, attached is a method that makes use of filesize to read a file and then display the results on a terminal in decimal and hexadecimal. Add this method and call it from the filesize code you have already. There is a change and an addition that needs to be included in your spin file, the change is to place the filesize variable in the VAR section eg: Word filesize. The addition is to add an array of 500 bytes to the VAR section eg: Byte buffer[512].

    I ran it a couple of times and it seemed ok, see what results it gives you it may need a tweak or two.

    Jeff T.

    Vadoo, in haste I forgot to include the instruction to close the file, you could make this the last instruction of the method.
  • VadooVadoo Posts: 92
    edited 2011-07-01 17:02
    I have read somewhere in my search, a recommendation to connect the VMusic2 reset pin to the Prop reset. But I can't seem to find this pin! Is there any other way? The issue/annoyance is each time I make a change to a program, I often have to change which instruction I send the
    Vmusic. For example if I had previously read 8 bytes of a file, the next time it will read the next 8 bytes rather then the first as I may want it to.
  • VadooVadoo Posts: 92
    edited 2011-07-01 18:25
    Vadoo, attached is a method that makes use of filesize to read a file and then display the results on a terminal in decimal and hexadecimal. Add this method and call it from the filesize code you have already. There is a change and an addition that needs to be included in your spin file, the change is to place the filesize variable in the VAR section eg: Word filesize. The addition is to add an array of 500 bytes to the VAR section eg: Byte buffer[512].

    I ran it a couple of times and it seemed ok, see what results it gives you it may need a tweak or two.

    Jeff T.

    Vadoo, in haste I forgot to include the instruction to close the file, you could make this the last instruction of the method.

    This seems to be working... I have gone all the way to adding in shift register control, and it is functional, not correctly, but expectedly as my code is a little off. I just haven't fixed that part yet.
    Right now I'm trying to figure out WHY it works... I tried so many variations of ways to read, store and re read the stored data. And many of them closely mimicked what you wrote, but mine didn't work! Anywho, I will post what I have done with what you sent once I refine It a little better. It's a bit messy right now.
    Thanks!!
  • VadooVadoo Posts: 92
    edited 2011-07-02 11:43
    This object is working great! It gets file size, reads to a 512 buffer and shifts it out. I can read entire sequence files now and control the shift registers! It does have one issue. It has to pause every couple seconds to refill the buffer. I'm working on a more complex program with multiple objects to fix that. I'll post that in a moment...
  • VadooVadoo Posts: 92
    edited 2011-07-02 11:55
    Here is my attempt to use one main object to manage two 512 buffers, and one object to shift out one buffer at a time and let the main object know when to refill one buffer while the other is being read. And so on.
    Its not working at all(as far as passing the data from cog to the other). I think I am passing the buffer (and other) addresses incorrectly. I know my shift object is working in some way. My heartbeat led does flash, but nothing on the shift registers.
  • VadooVadoo Posts: 92
    edited 2011-07-05 20:33
    I still can't figure out how to pass data from one cog to another... I'm trying to learn how to use @ properly but it hasn't clicked yet..
  • VadooVadoo Posts: 92
    edited 2011-07-06 11:03
    I'm trying to get this data, address stuff sorted out in my brain.
    Please tell me where I am off track.
    VAR
        byte temp1
    
    PUB Main
    
       temp1:= %11110000
    
    Temp is now equal to 11110000.
    Say I use:
    VAR
      long stack
    OBJ
      Shift: Shift_Out
    PUB
    .......................
      cognew(Shift.start(@temp1), @stack) 
    
    To start in its own cog:
    {Shift_Out.spin}
    
    PUB start(temp)
    
    At Shift_Out, temp is equal to the address of the data stored in temp1, not the data itself. Which could be something like $1AFF.
    To use the data store at that address I have to do something like:
        data:= byte(@temp)
    
    Now data is equal to %11110000.

    Am I on the right track at all?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 16:35
    Vadoo wrote: »
    I'm trying to get this data, address stuff sorted out in my brain.
    Please tell me where I am off track.
    VAR
    long stack
    OBJ
    Shift: Shift_Out
    PUB
    .......................
    cognew(Shift.start(@temp1), @stack) 
    
    To start in its own cog:

    You can start a method in a different object with new cog.

    You need to put the cognew call in the start method of your Shift object.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 16:41
    Vadoo wrote: »
    data:= byte(@temp)
    

    Should be :
    data := byte[temp]
    

    Since you passed the address of temp1, temp equals the address so you don't want to use the @ operator. @temp is the location of temp. temp holds the location of temp1.
  • VadooVadoo Posts: 92
    edited 2011-07-06 17:21
    Duane Degn wrote: »
    Since you passed the address of temp1, temp equals the address so you don't want to use the @ operator. @temp is the location of temp. temp holds the location of temp1.

    So temp is equal to byte(temp) which is %11110000, correct?
  • VadooVadoo Posts: 92
    edited 2011-07-06 17:23
    Duane Degn wrote: »
    You can start a method in a different object with new cog.

    You need to put the cognew call in the start method of your Shift object.
    Sorry I think I'm a little confused what you mean on this one.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 17:46
    Vadoo wrote: »
    Sorry I think I'm a little confused what you mean on this one.

    Sorry there were a couple of typos in my reply.

    You can not start a method in a different object in a new cog.

    You can't use MyObject.start with the cognew call.

    The method has to be part of the object where you use cognew. Cognew can not access a method within a child object.

    Instead you call the start method in a child object.
    OBJ
      MyObject : "MyObjectFileName"
    PUB
      MyObject.Start
    

    Then in the start method of MyObject you use cognew.
    VAR
      long stack[32]
    PUB Start
     
      cognew(MainLoop, @stack)
     
    PUB MainLoop
     
      repeat
        ' Do stuff in a different cog
     
     
    

    Hopefully and example and my not stating the opposite of what I mean, will help.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 17:52
    Vadoo wrote: »
    So temp is equal to byte(temp) which is %11110000, correct?

    This time I think you made the typo.

    You mean data equals %11110000, right? If so, yes.

    temp is set equal to the address of temp1.

    Also you need to use square brackets with byte[location] not ().
  • VadooVadoo Posts: 92
    edited 2011-07-06 17:58
    Duane Degn wrote: »
    This time I think you made the typo.

    You mean data equals %11110000, right? If so, yes.

    temp is set equal to the address of temp1.

    Also you need to use square brackets with byte[location] not ().

    Yes. That too. :) Thank you!!
    Though my intention was to say temp1 is the same as byte[temp]. Both statements would equal %11110000.
  • VadooVadoo Posts: 92
    edited 2011-07-06 18:12
    Duane Degn wrote: »
    VAR
      long stack[32]
    PUB Start
     
      cognew(MainLoop, @stack)
     
    PUB MainLoop
     
      repeat
        ' Do stuff in a different cog
     
     
    
    One question. If (using your example) I had PUB MainLoop(data), and needed cognew to send the address of the data stored in temp1 (our original object which originally stored the data to be used in our new cog), I can still just say cognew(MainLoop(temp), @stack) Because (temp) is the address, and saying @temp would give me the address of temp not the adddress stored in temp?
    I think I may have answered my own question but did that make sense?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 18:20
    Apparently this is not true:
    Duane Degn wrote: »
    You can't use MyObject.start with the cognew call.

    I hope kuroneko doesn't mind if I quote him.
    You can, it just isn't doing what people expect.

    I'll let someone who understands this better take it up.

    I'm trying to remember where I read the information about starting cogs in a child object. So far I don't remember.

    Duane
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-07-06 18:21
    Vadoo wrote: »
    One question. If (using your example) I had PUB MainLoop(data), and needed cognew to send the address of the data stored in temp1 (our original object which originally stored the data to be used in our new cog), I can still just say cognew(MainLoop(temp), @stack) Because (temp) is the address, and saying @temp would give me the address of temp not the adddress stored in temp?
    I think I may have answered my own question but did that make sense?

    Yes, it made sense and yes, you answered your own question.
  • kuronekokuroneko Posts: 3,623
    edited 2011-07-06 18:31
    re: cognew(MyObject.start, @stack{0})

    This looks OK but who knows why it doesn't do what one thinks it should do? Anyway, this particular case will do the method call and collect the result but will treat said result as an address to a PASM blob, i.e. like using cognew(@entry, 0). There are other oddities involving brackets but this isn't the thread for it.
Sign In or Register to comment.