Passing arrayref to C

Suppose I have:

%{^
uint8 funA(uint8* data) { return(0); } // Some array operation happens in
here
uint8_t data[256]; // Some place to hold data for funA to work with
%}

// A macro to access the data as an arrayref
macdef my_data =
$extval(arrayref(uint8, 256),“data”)

// And ATS version of the function
fun funA_ (cPtr0(uint8)) : uint8 = “mac#funA”

val v = funA_(ptr2cptr(my_data)) // The compiler does not like this

// Get a value for use
val v’ = my_data[0]

Given above, ptr2cptr does not work on the array ref. What is the proper
way to pass my_data into the C call?

The assumption here is that funA will never go beyond 256 values into the
passed in data. This is because of a hardware limitation where a count is a
byte. So it is safe. So if ATS deals with arrayref(uint8, 256), things
can’t get into trouble. But I need to pass the ATS array into C to get
something in hardware done.

A secondary question.

fun funB(val: arrayref(uint8,256)):uint8 =

val v = funB(my_data)

Is this the proper way to define a function that takes the arrayref? Or is
there some signature with and ‘&’ that does this like for a var?

I think there may have been a problem with my make. After a make clean, it
showed up.

Yep, was packing. This fixed it.

#pragma pack(push, 1)

typedef

struct {

uint8_t err;

uint16_t word;

} err_word;

#pragma pack(pop)

This can be done but it is a bit tricky.

Usually, such a function is given the following interface:

fun i2c_read_byte
(address: uint8, byte1: &uint8 >> _, byte2: &uint8 >> _): void

Also, how about the following interface:

fun i2c_read_byte(address: uint8): uint16On Wed, Nov 18, 2015 at 12:38 AM, Mike Jones proc...@gmail.com wrote:

Ok, I see now.

So now I have:

implement i2c_read_byte(address: uint8): (uint8, uint8) = let

How do I export this so that C can call it?

I saw from the book that the tuple becomes a struct. But it did not cover
how to make the function. Is there some example of how to do this?


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/a884f717-2c44-495a-ac84-eba74765ee57%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/a884f717-2c44-495a-ac84-eba74765ee57%40googlegroups.com?utm_medium=email&utm_source=footer
.

Oh, I was reading after that point and missed that paragraph. I’ll test now
and confirm the array ref passes a pointer, etc.

Interesting :)On Wednesday, November 18, 2015 at 2:01:42 PM UTC-5, Mike Jones wrote:

Yep, was packing. This fixed it.

#pragma pack(push, 1)

typedef

struct {

uint8_t err;

uint16_t word;

} err_word;

#pragma pack(pop)

Why funA_ is not given the following type instead:

fun funA_ : arrayref(uint8, 256) → uint8

val v = funA_(ptr2cptr(my_data)) // The compiler does not like this

ptr2cptr takes pointer but my_data is an arrayref.

fun funB(val: arrayref(uint8,256)):uint8 =

Yes. ‘val’ is a keyword and should probably be replaced.On Tue, Nov 17, 2015 at 8:04 PM, Mike Jones proc...@gmail.com wrote:

Suppose I have:

%{^
uint8 funA(uint8* data) { return(0); } // Some array operation happens in
here
uint8_t data[256]; // Some place to hold data for funA to work with
%}

// A macro to access the data as an arrayref
macdef my_data =
$extval(arrayref(uint8, 256),“data”)

// And ATS version of the function
fun funA_ (cPtr0(uint8)) : uint8 = “mac#funA”

val v = funA_(ptr2cptr(my_data)) // The compiler does not like this

// Get a value for use
val v’ = my_data[0]

Given above, ptr2cptr does not work on the array ref. What is the proper
way to pass my_data into the C call?

The assumption here is that funA will never go beyond 256 values into the
passed in data. This is because of a hardware limitation where a count is a
byte. So it is safe. So if ATS deals with arrayref(uint8, 256), things
can’t get into trouble. But I need to pass the ATS array into C to get
something in hardware done.

A secondary question.

fun funB(val: arrayref(uint8,256)):uint8 =

val v = funB(my_data)

Is this the proper way to define a function that takes the arrayref? Or is
there some signature with and ‘&’ that does this like for a var?


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/e5d3c479-17fa-449a-a0da-641573f976ab%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/e5d3c479-17fa-449a-a0da-641573f976ab%40googlegroups.com?utm_medium=email&utm_source=footer
.

Are you saying the following below would work? That by defining funA_ with
an array ref a pointer would be passed to the C version funA?

%{^
uint8 funA(uint8* data) { return(0); } // Some array operation happens in
here
uint8_t data[256]; // Some place to hold data for funA to work with
%}

fun funA_ (arrayref(uint8, 256) : uint8 = “mac#funA”

Ok, I see now.

So now I have:

implement i2c_read_byte(address: uint8): (uint8, uint8) = let

How do I export this so that C can call it?

I saw from the book that the tuple becomes a struct. But it did not cover
how to make the function. Is there some example of how to do this?

Ok, I’m closer. Compiles. Runs. But having some problem with return values.

In ATS:

%{^
uint8_t i2c_data[256];
%}

macdef i2c_data =
$extval(arrayref(uint8, 256),“i2c_data”)

fun i2c_read_byte_data (uint8, uint8)
: (uint8, uint8) = "ext#i2c_read_byte_data_c"
implement i2c_read_byte(address: uint8): (uint8, uint8) = let
var err: uint8 = err (0, u8)
val () = ifnerr(i2c_start(), err, 1, u8)
val () = ifnerr(i2c_write(wa address), err, 2, u8)
val () = ifnerr(i2c_repeated_start(), err, 3, u8)
val () = ifnerr(i2c_read(), err, 4, u8)
val () = ifnerr(i2c_stop(i2c_data), err, 5, u8)
in (err, i2c_data[0]) end

In C, supporting i2c_stop(i2c_data) above in ATS:

uint8_t i2c_stop(uint8_t *data)
{
CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

CyU3PDebugPrint (2, “I2C Stop\r\n”);

if (read)
{
status = CyU3PI2cReceiveBytes (&shared_preamble, shared_data,
shared_data_len, 0);
memcpy(data, shared_data, shared_data_len);
}
else
{
if (shared_data_len == 0)
shared_data[shared_data_len++] =
shared_preamble.buffer[–shared_preamble.length];
status = CyU3PI2cTransmitBytes (&shared_preamble, shared_data,
shared_data_len, 0);
}

return((uint8_t)status);
}

In C application code:

typedef

struct {

uint8_t err;

uint16_t byte;

} err_byte;

extern err_byte i2c_read_byte_data_c(uint8_t, uint8_t);

err_byte sb;

uint8_t b; 

sb = i2c_read_byte_data_c(0x30, 0x00);

status = sb.err;

b = sb.byte;

In the debugger while stopped inside i2c_stop() (C code), I look at
i2c_data and see that it is set to 0x01. But what is returned to the
err_byte struct is a 0x00.

This implies that in the ATS, the code in (err, i2c_data[0]) end is failing
to index into the C array i2c_data, or the mapping to the returned struct
is failing. Is there some problem with my C declaration of the struct?
Could there be a memory alignment issue requiring some forced packing or
something?

Note this is a 32 bit ARM 9. And I am not using the C99 option during
compilation, I’m using whatever the default is for the Cypress make system.

If i2c_read_byte_data is implemented, then the compiler should generate
i2c_read_byte_data_c.On Wed, Nov 18, 2015 at 11:12 AM, Mike Jones proc...@gmail.com wrote:

The compiler seems to generate the _c names for the write, but not the
read. Looks like the compiler can’t handled the struct return and just
ignores the ext def.

fun i2c_read_byte_data (uint8, uint8)
: (uint8, uint8) = “ext#i2c_read_byte_data_c”
fun i2c_write_byte_data (uint8, uint8, uint8)
: uint8 = “ext#i2c_write_byte_data_c”
fun i2c_read_word_data (uint8, uint8)
: (uint8, uint16) = “ext#i2c_read_word_data_c”
fun i2c_write_word_data (uint8, uint8, uint16)
: uint8 = “ext#i2c_write_word_data_c”


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/4d58850c-9d05-4dea-bbe4-1c16a8e8bcaf%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/4d58850c-9d05-4dea-bbe4-1c16a8e8bcaf%40googlegroups.com?utm_medium=email&utm_source=footer
.

It seems that you need the following line:

staload _ = "prelude/DATS/unsafe.dats"On Wed, Nov 18, 2015 at 12:03 AM, Mike Jones proc...@gmail.com wrote:

I only used different names to make the example clear.

I’m having difficulty getting it to compile, so here is the exact code:

fun i2c_stop (arrayref(uint8, 256))
: uint8 = “mac#i2c_stop”

%{^
uint8_t i2c_data[256];
%}

macdef i2c_data =
$extval(arrayref(uint8, 256),“i2c_data”)

implement i2c_read_byte(address: uint8): (uint8, uint8) = let
var b: uint8 = u8(0)
var err: uint8 = err (0, u8)
val () = ifnerr(i2c_start(), err, 1, u8)
val () = ifnerr(i2c_write(wa address), err, 2, u8)
val () = ifnerr(i2c_read(), err, 3, u8)
val () = ifnerr(i2c_stop(i2c_data), err, 4, u8)
in (err, i2c_data[0]) end

I’m getting errors like:

/*
emit_instr: loc0 = /opt/ATS/ATS2-Postiats-0.2.4/prelude/DATS/array.dats:
1971(line=63, offs=45) – 1989(line=63, offs=63)
*/
ATSINSmove(tmpret33__1,
PMVtmpltcstmat[0](ptr0_get<S2Eapp(S2Ecst(g0uint_t0ype);
S2Eextkind(atstype_uint8))>)(tmp34__1)) ;

DATS/smbus_dats.c:1036:43: error: ‘ptr0_get’ undeclared (first use in this
function)
ATSINSmove(tmpret33__1,
PMVtmpltcstmat[0](ptr0_get<S2Eapp(S2Ecst(g0uint_t0ype);
S2Eextkind(atstype_uint8))>)(tmp34__1)) ;

DATS/smbus_dats.c:1036:66: error: ‘g0uint_t0ype’ undeclared (first use in
this function)
ATSINSmove(tmpret33__1,
PMVtmpltcstmat[0](ptr0_get<S2Eapp(S2Ecst(g0uint_t0ype);
S2Eextkind(atstype_uint8))>)(tmp34__1)) ;


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/34bf8276-27ff-4fd9-851e-c7c37179d76e%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/34bf8276-27ff-4fd9-851e-c7c37179d76e%40googlegroups.com?utm_medium=email&utm_source=footer
.

By the way, I would like to suggest a different style, which you
may try later when you become more comfortable with ATS.

When I see:

uint8_t data[256];

my immediate reflex is that I can now have the following two functions:

fun{} data_get_at : natLt(256) → uint8
fun{} data_set_at : (natLt(256), uint8) → void

If ‘data’ is read-only, then ‘data_set_at’ is not available. Also, ‘data’
can be
shared among threads if that is what you want.

If you really need to call ‘funA’ in ATS, you can do

val () = $extfcall(void, “funA”, $extval(ptr, “data”))On Tue, Nov 17, 2015 at 8:04 PM, Mike Jones proc...@gmail.com wrote:

Suppose I have:

%{^
uint8 funA(uint8* data) { return(0); } // Some array operation happens in
here
uint8_t data[256]; // Some place to hold data for funA to work with
%}

// A macro to access the data as an arrayref
macdef my_data =
$extval(arrayref(uint8, 256),“data”)

// And ATS version of the function
fun funA_ (cPtr0(uint8)) : uint8 = “mac#funA”

val v = funA_(ptr2cptr(my_data)) // The compiler does not like this

// Get a value for use
val v’ = my_data[0]

Given above, ptr2cptr does not work on the array ref. What is the proper
way to pass my_data into the C call?

The assumption here is that funA will never go beyond 256 values into the
passed in data. This is because of a hardware limitation where a count is a
byte. So it is safe. So if ATS deals with arrayref(uint8, 256), things
can’t get into trouble. But I need to pass the ATS array into C to get
something in hardware done.

A secondary question.

fun funB(val: arrayref(uint8,256)):uint8 =

val v = funB(my_data)

Is this the proper way to define a function that takes the arrayref? Or is
there some signature with and ‘&’ that does this like for a var?


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/e5d3c479-17fa-449a-a0da-641573f976ab%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/e5d3c479-17fa-449a-a0da-641573f976ab%40googlegroups.com?utm_medium=email&utm_source=footer
.

Ok, let’s start with a simpler one:

fun i2c_write_byte_data (uint8, uint8, uint8)
: uint8
implement i2c_read_byte_data(address: uint8, command: uint8): (uint8,
uint8) = let

This generated:
/*
local: wa_0$0(level=0)
global: wa_0$0(level=0), i2c_write_byte_data$54$0(level=0)
local:
global:
*/
ATSextern()
atstkind_t0ype(atstype_uint8)
_057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(atstkind_t0ype(atstype_uint8)
arg0, atstkind_t0ype(atstype_uint8) arg1, atstkind_t0ype(atstype_uint8)
arg2)
{

I then call it like this:

extern
uint8_t _057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(uint8_t
arg0, uint8_t arg1, uint8_t arg2);

uint8_t v
= _057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(0x00,
0x00, 0x00);

And it compiles. But what is a good way to deal with this long prefix? All
I can think of is to wrap a macro around it like:

#define i2c_write_byte_data
_057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data

But this will result in messy compiler errors.

I had this:
staload “prelude/SATS/unsafe.sats”

But this works when added:
staload _ = “prelude/DATS/unsafe.dats”

The compiler seems to generate the _c names for the write, but not the
read. Looks like the compiler can’t handled the struct return and just
ignores the ext def.

fun i2c_read_byte_data (uint8, uint8)
: (uint8, uint8) = "ext#i2c_read_byte_data_c"
fun i2c_write_byte_data (uint8, uint8, uint8)
: uint8 = "ext#i2c_write_byte_data_c"
fun i2c_read_word_data (uint8, uint8)
: (uint8, uint16) = "ext#i2c_read_word_data_c"
fun i2c_write_word_data (uint8, uint8, uint16)
: uint8 = “ext#i2c_write_word_data_c”

It should work.

By the way, you could just use the name ‘funA’ for ‘funA_’.On Tue, Nov 17, 2015 at 11:02 PM, Mike Jones proc...@gmail.com wrote:

Are you saying the following below would work? That by defining funA_ with
an array ref a pointer would be passed to the C version funA?

%{^
uint8 funA(uint8* data) { return(0); } // Some array operation happens in
here
uint8_t data[256]; // Some place to hold data for funA to work with
%}

fun funA_ (arrayref(uint8, 256) : uint8 = “mac#funA”


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/7c85fe9a-3530-4b88-a65d-6527ecc12e8f%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/7c85fe9a-3530-4b88-a65d-6527ecc12e8f%40googlegroups.com?utm_medium=email&utm_source=footer
.

ptr0_get is a template whose definition is in unsafe.dats.
So you need to staload unsafe.dats (not just unsafe.sats).
Otherwise, the compiler would not be able to compile ptr0_get
(and you saw error messages saying something about PMVtmpltcstmat[0])On Wed, Nov 18, 2015 at 12:23 AM, Mike Jones proc...@gmail.com wrote:

I had this:
staload “prelude/SATS/unsafe.sats”

But this works when added:
staload _ = “prelude/DATS/unsafe.dats”


You received this message because you are subscribed to the Google Groups
“ats-lang-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to ats-lang-user...@googlegroups.com.
To post to this group, send email to ats-lan...@googlegroups.com.
Visit this group at http://groups.google.com/group/ats-lang-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/ats-lang-users/f47ac698-802c-4861-8ee4-5fee0023cf89%40googlegroups.com
https://groups.google.com/d/msgid/ats-lang-users/f47ac698-802c-4861-8ee4-5fee0023cf89%40googlegroups.com?utm_medium=email&utm_source=footer
.

The following line cause a type of the name ‘uint8_pair_t’
to be defined in the generated C code:

extern typedef “uint8_pair_t” = (uint8, uint8)

So the interface for i2c_read_byte in C is

extern
uint8_pair_t i2c_read_byte (uint8_t address) ;On Wednesday, November 18, 2015 at 12:47:34 AM UTC-5, Mike Jones wrote:

Note, calling this from C is silly, but I want to test before I wrap a
whole state machine around it. Even so, eventually, even that has to be
called from C. So the need is general.

This issue is mention in Chapter 8 of the Intro-to-ATS book:

http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/HTMLTOC/c2005.html

extern
fun i2c_write_byte_data (…): … =
"ext#whatever_name_you_like_in_c_for_this_function"On Wednesday, November 18, 2015 at 9:42:03 AM UTC-5, Mike Jones wrote:

Ok, let’s start with a simpler one:

fun i2c_write_byte_data (uint8, uint8, uint8)
: uint8
implement i2c_read_byte_data(address: uint8, command: uint8): (uint8,
uint8) = let

This generated:
/*
local: wa_0$0(level=0)
global: wa_0$0(level=0), i2c_write_byte_data$54$0(level=0)
local:
global:
*/
ATSextern()
atstkind_t0ype(atstype_uint8)
_057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(atstkind_t0ype(atstype_uint8)
arg0, atstkind_t0ype(atstype_uint8) arg1, atstkind_t0ype(atstype_uint8)
arg2)
{

I then call it like this:

extern
uint8_t _057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(uint8_t
arg0, uint8_t arg1, uint8_t arg2);

uint8_t v
= _057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data(0x00,
0x00, 0x00);

And it compiles. But what is a good way to deal with this long prefix? All
I can think of is to wrap a macro around it like:

#define i2c_write_byte_data
_057_home_057_mike_057_cypress_057_workspace_057_UsbI2cRegMode_057_SATS_057_smbus_056_sats__i2c_write_byte_data

But this will result in messy compiler errors.