Home AMX User Forum AMX On-Demand Classes & Certifications

Copying info from a .TXT file

I need to copy an IP address from a txt file that is stored on the master. Any links that would explain this much appreciated, my search has so far been fruitless.

Thanks

«1

Comments

  • HARMAN_ChrisHARMAN_Chris Posts: 597

    Text file operations are covered in Exercise 7 of the CP232 instructor led course. We are working on capturing this course in an On Demand series and expect it to be available shortly. I presume you will receive code suggestions from forum posters before this goes live, but I would encourage you to check out the CP231 On Demand course once it is released.

  • PatGPatG Posts: 42

    OK thanks

  • sentry07sentry07 Posts: 77

    Check the help file for FILE_OPEN, FILE_READ_LINE, FILE_CLOSE, etc. Those functions give you what you need to open a file with a file handle, read lines from it, and close the file handle.

  • ericmedleyericmedley Posts: 4,177

    do NOT forget to close your files when you are done. :)

  • PatGPatG Posts: 42

    I can now open/ close and read the file but getting the info out of it and into a structure ( which I'm pretty sure I need to use ) escapes me. Would that course capture be online yet?

  • ericmedleyericmedley Posts: 4,177

    Post some code and maybe we can help you. It's honestly not difficult.

  • PatGPatG Posts: 42

    OK so here's what I have so far:

           nIPfile = FILE_OPEN ('IP_ADDRESSING2.txt', FILE_READ_ONLY)
        nMaster_IP = FILE_READ(nIPFile, cFile_BUFFER, 29) 
        IP_CLIENT_OPEN (cFile_BUFFER)
        nIPfile = FILE_CLOSE (nIPFile) 
        CLEAR_BUFFER cFile_BUFFER
    

    cFile_BUFFER has everything I need in it in the form of a string. So I guess my main problem is using it to open the port.

    For example, if I use

    IP_CLIENT_OPEN(dvLights.PORT,cLightControl_IP,24,IP_TCP

    it works fine, but I didn't get that info from the, file I just put it in there.

    Thanks

  • ericmedleyericmedley Posts: 4,177

    @PatG said:
    OK so here's what I have so far:

           nIPfile = FILE_OPEN ('IP_ADDRESSING2.txt', FILE_READ_ONLY)
      nMaster_IP = FILE_READ(nIPFile, cFile_BUFFER, 29) 
      IP_CLIENT_OPEN (cFile_BUFFER)
      nIPfile = FILE_CLOSE (nIPFile) 
      CLEAR_BUFFER cFile_BUFFER
    

    cFile_BUFFER has everything I need in it in the form of a string. So I guess my main problem is using it to open the port.

    For example, if I use

    IP_CLIENT_OPEN(dvLights.PORT,cLightControl_IP,24,IP_TCP

    it works fine, but I didn't get that info from the, file I just put it in there.

    Thanks

    Okay, for starters you might not be using Open_File correctly.

    nMaster_IP = FILE_READ(nIPFile, cFile_BUFFER, 29)

    I don't know what nMaster_IP is but the value the function FILE_READ spits out is a signed integer. If the value returned is less than zero it indicates some kind of error occured when attempting to read the file. A value of zero or greater is the number of bytes returned up to the end of file.

    Also in the statement: "IP_CLIENT_OPEN (cFile_BUFFER)" I'm surprised this even compiled.

    The format for this function is;

    result=ip_client_open(integer local_port_id,char IP_ADDRESS,long Server_Port, integer protocol)

    result is a signed integer that reports a value code to let you know the success/failure of the attempt to connect to a remote server port.
    local_port is the port given by the DEFINE_DEVICE section of code you chose to create the client. ex:

    DeFINE_DEVICE

    dv_My_IP_Client = 0:4:0 // an ip client on netlixn ip port 4

    IP_ADDRESSW is a string containing the IP Address of the server you're trying to reach.

    Server_Por is long variable or value that ijndicates the remote server's IP port. (ex: 80 for a web server...)

    protocol is an integer to tell the processor which method to connect to the remote server.
    1 = TCP
    2 = UDP
    3 = UDP with Receive

    Bear in mind the IP_Client_Open command doesn't actually send anything or recieve anything. IP communication is merely established with the remote server. It's up to you to manage the asyncronous communication. Usually you need to set up a data_event that watches the online and offline status of the IP port. when the port comes online you usually need to send something to initiate the conversation (like the GET command of a web server or return key of a telent session or whatnot.) Also you monitor the string returns in the same data_event. To send messages to the server you use the
    Send_String dv_My_IP_Client, 'A string to the IP server'

    you may also need to manage the IP connection itself. In the case of many servers (like a web server) they will only stay alive for a quick session like one message in and a respojnse. then it shuts you down.

    Other servers might allow you to leave the port open as long as you say something every now and then. If you're quiet too long it shuts you down.

    Still other servers will leave you connected as long as you want and never try to shut you down until you say so.

    In each case it's up to you to manage this connection and be proactive about maintaining it until you are done.

    Those are some hopfully helpful hints.
    e

  • And while were on it, could you post what's in 'IP_ADDRESSING2.txt'?

  • Try something like the code below. It opens a file and will read up to 1000 records with a max length of 200 bytes per line. It assumes it is a DOS text file with CR/LF at the end of each line. The line read gets stored in the array cCFGLINE. Each array element contains one line read from the file. You can then use whatever string functions you need to extract the data you need. If you only need to read one line, don't do the for loop and just read one line the info read will be in that stack_var "line". When it is finished, nCONFIGMAX contains the number of record read from the file.

    I copied this from an existing program and may have missed a variable or two but it should give you an idea of where to start. I use this to have a file of xConfiguration commands for a cisco video codec where I just shoot the lines in the array to the codec to do a configuration. So I'm not grabbing anything out of the line before I send it on. But if you know what you are looking for you can do the string functions to pull what you need from the line.

    DEFINE_VARIABLE

    CHAR strFILE[] = 'CONFIG.TXT'
    INTEGER nCONFIGMAX
    VOLATILE CHAR cCFGLINE[1000] [200]

    DEFINE_FUNCTION CFGLOAD()
    {
    STACK_VAR CHAR line[200]
    STACK_VAR INTEGER i
    STACK_VAR SLONG bytes
    STACK_VAR SLONG file

    bytes = 1
    
    file = FILE_OPEN(strFILE,1)  
    
    IF (file > 0)
    {
          nCONFIGMAX=0
    
                // READ ALL RECORDS
    
        FOR (i = 1; ((bytes > 0) AND i < 1001); i++)
        {
                 bytes=FILE_READ_LINE(file, line, 200)
        IF (bytes > 1)
        {
        cCFGLINE[i]=line
        nCONFIGMAX=nCONFIGMAX+1
        }
    
        }
        FILE_CLOSE(file)
    }          
    

    }

  • PatGPatG Posts: 42

    Thanks. I'm probably not explaining myself properly. IP_CLIENT_OPEN (cFile_BUFFER) doesn't compile, I was just giving an example of where the data is and what I need it for.

    nMaster_IP is just a bad choice of words for that variable. I am able to open the file and get the info I need but not into the format that I need it.
    As I mentioned above I can get the port open and have it work and stay open, but that's when I use the line of code that has device and IP address, etc. previously defined. What I need to do is get all that info from the file, not populate it myself. And I am not sure how to get it from the buffer into the formats it should be in.
    I need a device first, then a string, then an integer and then another string from what I can tell but when I take the parts out in order and try to manipulate them from that string it doesn't like anything I try. Also defining a device in this way has me baffled.

    Thanks for your time and patience.

  • MLaletasMLaletas Posts: 226

    In your example what does the variable cFile_BUFFER in debugger look like when it reads?

  • sYoonsYoon Posts: 1

    @PatG said:
    Thanks. I'm probably not explaining myself properly. IP_CLIENT_OPEN (cFile_BUFFER) doesn't compile, I was just giving an example of where the data is and what I need it for.

    nMaster_IP is just a bad choice of words for that variable. I am able to open the file and get the info I need but not into the format that I need it.
    As I mentioned above I can get the port open and have it work and stay open, but that's when I use the line of code that has device and IP address, etc. previously defined. What I need to do is get all that info from the file, not populate it myself. And I am not sure how to get it from the buffer into the formats it should be in.
    I need a device first, then a string, then an integer and then another string from what I can tell but when I take the parts out in order and try to manipulate them from that string it doesn't like anything I try. Also defining a device in this way has me baffled.

    Thanks for your time and patience.

    I am assuming you already confirmed that you read correct data into cFile_BUFFER.
    If you haven't, try log it to console using 'amx_log' or good old 'send_string 0' first to confirm the data read is what you need.

    what is in cFile_BUFFER is string, indeed more like array of bytes.
    Your definition must be char[] I suppose.
    So you need to 'PARSE' text data into all the integers and strings you need.
    If you are not interested in 'PARSING' date, have a look at help of below two functions and give a go.

    'xml_to_variable'
    'variable_to_xml'

    Cheers
    Sam

  • PatGPatG Posts: 42

    @MLaletas said:
    In your example what does the variable cFile_BUFFER in debugger look like when it reads?

    I have:

    0:4:0,134.117.119.220,24,tcp

    Which is what it should be.

  • MLaletasMLaletas Posts: 226

    so if cFile_BUFFER contains that whole string then theres your problem. You mention earlier you realize that the IP_CLIENT_OPEN( cFile_BUFFER ) doesnt compile it was just for illustration I would like to see what you are actually using to open the socket? If the desired result is to populate all four field (DPS, IP address, IP Port, Protocol you might want to start with a different methodology, at least thats my opinion. For the interim you could start small, have that just be your IP address and confirm that works. For example is here the structure that I use that dynamically handles DPS, Address and port (not protocol never felt the need)

    IP_CLIENT_OPEN( dvDEV.port, AudioDev.ControlIP, AudioDev.ControlIPPort, IP_TCP )
    

    Assuming your successful there you can continue on your grandplan. If you want your file to look the same as what you posted above you would just need to parse accordingly. For I use self made config files with the appropriate parsing using self made "protocol", for example:

    Audio 1: ControlDeviceID-0:4:0
    Audio 1: ControlIP-134.117.119.220
    Audio 1: ControlIPPort-24
    

    As an FYI when you read in the DPS you will need to account that you cant just throw that into a string, an illustration of that:

    STACK_VAR DEV lvDEV
    lvDEV.number = ATOI( cNumber )
    lvDEV.port = ATOI( cPort )  
    lvDEV.system = ATOI( cSystem )
    AudioDev.ControlDev = lvDEV
    

    Does any of that make sense, or am I misinterpeting what your trying to do/achieve?

  • PatGPatG Posts: 42

    @MLaletas said:
    so if cFile_BUFFER contains that whole string then theres your problem. You mention earlier you realize that the IP_CLIENT_OPEN( cFile_BUFFER ) doesnt compile it was just for illustration I would like to see what you are actually using to open the socket? If the desired result is to populate all four field (DPS, IP address, IP Port, Protocol you might want to start with a different methodology, at least thats my opinion. For the interim you could start small, have that just be your IP address and confirm that works. For example is here the structure that I use that dynamically handles DPS, Address and port (not protocol never felt the need)

    IP_CLIENT_OPEN( dvDEV.port, AudioDev.ControlIP, AudioDev.ControlIPPort, IP_TCP )
    

    Assuming your successful there you can continue on your grandplan. If you want your file to look the same as what you posted above you would just need to parse accordingly. For I use self made config files with the appropriate parsing using self made "protocol", for example:

    Audio 1: ControlDeviceID-0:4:0
    Audio 1: ControlIP-134.117.119.220
    Audio 1: ControlIPPort-24
    

    As an FYI when you read in the DPS you will need to account that you cant just throw that into a string, an illustration of that:

    STACK_VAR DEV lvDEV
    lvDEV.number = ATOI( cNumber )
    lvDEV.port = ATOI( cPort )    
    lvDEV.system = ATOI( cSystem )
    AudioDev.ControlDev = lvDEV
    

    Does any of that make sense, or am I misinterpeting what your trying to do/achieve?

    This looks like exactly the kind of thing I was looking for, thank you, I'm going to try with this info.

  • PatGPatG Posts: 42

    So far I have come up with this:

    `DEFINE_FUNCTION fnLightingSetup()
    {
    //IP_CLIENT_OPEN(dvLights.PORT,cLightControl_IP,24,IP_TCP)

    nIPfile = FILE_OPEN ('IP_ADDRESSING2.txt', FILE_READ_ONLY)
    nLength_IP = FILE_READ(nIPFile, cFile_BUFFER, 29) 
    
    cIP_ADD = MID_STRING (cFile_BUFFER, 7, 15)
    cPort = MID_STRING (cFile_BUFFER, 23, 2) 
    cProtocol = MID_STRING (cFile_BUFFER, 26, 3)
    
    cDevNumber = MID_STRING (cFile_BUFFER, 1, 1)
    cDevPort = MID_STRING (cFile_BUFFER, 3, 1)
    cDevSystem = MID_STRING (cFile_BUFFER, 5, 1)
    
    sDevice.nNumber = ATOI (cDevNumber)
    sDevice.nPort = ATOI (cDevPort)    
    sDevice.nSystem = ATOI (cDevSystem)
    
    IP_CLIENT_OPEN (sDevice.PORT,cIP_ADD,ATOI(cPort),cProtocol)
    WAIT 20
    {
    nIPfile = FILE_CLOSE (nIPFile) 
    CLEAR_BUFFER cFile_BUFFER
    }
    

    }`

    It compiles but doesn't work. It occurs to me I am trying to define a device outside of and even after the DEFINE_DEVICE section and all other instances where I need the device will have to use the info from the file, and NOT from the define_device section. ( That first commented line is the one I use that I know works to make sure it's not a network issue. ) The more I think about this the closer I get to an existential crisis. I suspect I'm not using the structure quite right here it is:

    STRUCT _uDEVICE { INTEGER nNumber INTEGER nPort INTEGER nSystem INTEGER PORT }

    Anyway that's where I'm at any insight much appreciated.

  • We can get you through this man, no big deal.

    Check debug and see what the current value of cIP_ADD, cPort and cProtocol (Which btw you need to fix that parameter is an integer so you might want to do another ATOI), what are those values?

    Next your sDevice isnt right. In my example I had a DEV as the data type it appears you made a selfmade struct, I actually didnt know if a selfmade one would work so i tried it out and it did, although I would recommend using the supplied DEV as your datatype but thats just me. The thing with yours is you have four parameters, you only need three. When your opening the IP_CLIENT you would want to use sDevice.nPort in your particular case as the first parameter since you are using a selfmade one.

    Lastly once you get this working you will need to use REBUILD_EVENT() so that your data devents work with your dynamic device, hopefully that helps

  • ericmedleyericmedley Posts: 4,177

    One thing I'd suggest is to use a delineator to separate you data in your file. That way you don't have to do all the byte counting and mid_string stuff. This will help also in that the IP Address is not always going to be the same sized string.

    For example, you could make the file format:




    etc...

    Then you can just use the file_read_line function. This function will start at the beginning of the file and give you the string up to the first carriage return, then stops. Internally a pointer is set so the next file_read_line call starts where it left off last. You can just call the function in succession to get all your data cells without having to deal with the varying sizes of the data cells. The file_read_line function also will let you know when you've reached the end of the file which helps you to know when you're done or that something went wrong.
    e

  • Oh, that's a cliffhanger :D Saying how the file should be formatted and then leaving that part out....
    Now we have to wait for your next post B)

    BTW: why does your 'profile line' say: 'Senior Member-3709 Posts Posts:4154' ??

  • @richardherman said:
    Oh, that's a cliffhanger :D Saying how the file should be formatted and then leaving that part out....
    Now we have to wait for your next post B)

    BTW: why does your 'profile line' say: 'Senior Member-3709 Posts Posts:4154' ??

    Its conveniently blank.

  • PatGPatG Posts: 42

    Attached are the values of the variables, which are all correct, except for the contents of the structure where ATOI doesn't get me what I had hoped for. Also the code as I have it now

    `DEFINE_FUNCTION fnLightingSetup()
    {
    //IP_CLIENT_OPEN(dvLights.PORT,cLightControl_IP,24,IP_TCP)

    nIPfile = FILE_OPEN ('IP_ADDRESSING2.txt', FILE_READ_ONLY)
    nLength_IP = FILE_READ(nIPFile, cFile_BUFFER, 29) 
    
    cIP_ADD = MID_STRING (cFile_BUFFER, 7, 15)
    cPort = MID_STRING (cFile_BUFFER, 23, 2) 
    cProtocol = MID_STRING (cFile_BUFFER, 26, 3)
    
    cDevNumber = MID_STRING (cFile_BUFFER, 1, 1)
    cDevPort = MID_STRING (cFile_BUFFER, 3, 1)
    cDevSystem = MID_STRING (cFile_BUFFER, 5, 1)
    
    sDevice.nNumber = ATOI (cDevNumber)
    sDevice.nPort = ATOI (cDevPort)    
    sDevice.nSystem = ATOI (cDevSystem)
    
    IP_CLIENT_OPEN (sDevice.nPort,cIP_ADD,ATOI(cPort),ATOI(cProtocol))
    WAIT 20
    {
    nIPfile = FILE_CLOSE (nIPFile) 
    CLEAR_BUFFER cFile_BUFFER
    }
    

    }`

    https://1drv.ms/u/s!ArFKA2S5tL7NhVaB9SUnH8RJ8FJj?e=w0MFkS

  • MLaletasMLaletas Posts: 226
    edited September 2019

    your cProtocol value is "tcp", that parameter wants an integer 1 (TCP), 2 (UDP), 3 (UDP with Receive). So either replace tcp with a 1 in your file or create some conditional to allow cProtocol to become a 1.

    Also it looks like your sDevice is not reading right as its all 0's, I see that your cDev variables are reading right

  • ericmedleyericmedley Posts: 4,177
    edited September 2019

    @MLaletas said:

    @richardherman said:
    Oh, that's a cliffhanger :D Saying how the file should be formatted and then leaving that part out....
    Now we have to wait for your next post B)

    BTW: why does your 'profile line' say: 'Senior Member-3709 Posts Posts:4154' ??

    Its conveniently blank.

    Oh wow! I had the text there but I put the lines in with <
    and >

    it should have said:
    IP Addres Text - then a CR at the end of the line
    IP Port Text - then a CR at the end of the line
    IP Protocol - then a CR at the end of the line.
    etc...

    Sorry about th

    My profile count is not something I entered. .. but I have been a forum member for many many years and I do have over 4000 posts. I don't know If I'm the top poster but I was up there next to D Hawthorne and Dan Vining. In other words: I'm old.
    e

  • PatGPatG Posts: 42
    edited September 2019

    @MLaletas said:
    your cProtocol value is "tcp", that parameter wants an integer 1 (TCP), 2 (UDP), 3 (UDP with Receive). So either replace tcp with a 1 in your file or create some conditional to allow cProtocol to become a 1.

    Also it looks like your sDevice is not reading right as its all 0's, I see that your cDev variables are reading right

    Yeah I'm not sure what is going on with sDevice and why ATOI isn't doing what I'd hoped.

    As for TCP thanks for the info on that, I'm stuck using whatever is in the file but I think I know how I can make it work.

  • @ericmedley were just messing with you buddy, as far as being old its no problem you'll find the fountain of youth im certain!

    @PatG with your sDevice I think your better bet is to go with a DEV datatype instead of your own structure, but thats just me. Theres some other things that could be modified, some of them are personal preference, maybe some best practices and whatnot but seems like your on the right track.

  • @ericmedley ha, I know you've been around here a long time, I believe I already read your posts when I joined the forum back in 2005. Always liked your posts, positive, looking for solutions. And it means you could be older than me. Wow... :o
    The first part of your profile line, the 'Senior Member-3709 Posts' part is probably something that can be changed in your profile, the post count is added automatically (now). I know I replaced the 'Junior Member' with 'not so Junior Member', because that's just closer to the truth. o:)

  • PatGPatG Posts: 42

    I got it working! Thanks for your help everybody. The final fix was so simple I never thought of it.

  • ericmedleyericmedley Posts: 4,177

    "Did you ever notice the thing you're trying so hard to find is always in the last place you look?"

  • John NagyJohn Nagy Posts: 1,734

    @ericmedley said:
    "Did you ever notice the thing you're trying so hard to find is always in the last place you look?"

    That MIGHT be related to the tendency to stop looking for it once you find it....

Sign In or Register to comment.