summaryrefslogtreecommitdiffhomepage
path: root/digital/avr/modules/twi/twi.host.c
blob: 036905b3b624646af5521ac4d8b41c405bca5a2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/* twi.host.c - Implementation for host system. */
/* avr.twi - TWI AVR module. {{{
 *
 * Copyright (C) 2008 Nicolas Schodet
 *
 * APBTeam:
 *        Web: http://apbteam.org/
 *      Email: team AT apbteam DOT org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * }}} */
#include "common.h"
#include "twi.h"

#include "modules/utils/utils.h"
#include "modules/host/host.h"
#include "modules/host/mex.h"
#include <string.h>

/** Read messages are sent as request.
 * In request, first byte is address, second byte is length.
 * In response, whole payload is data. */

/** Write messages are sent directly.
 * First byte is address, rest of payload is data. */

/** Module context. */
struct twi_host_t
{
    /** Slave address. */
    uint8_t address;
#if AC_TWI_SLAVE_ENABLE
    /** Slave transmission buffer. */
    uint8_t slave_send_buffer[AC_TWI_SLAVE_SEND_BUFFER_SIZE];
    /** Slave transmission buffer current size. */
    uint8_t slave_send_buffer_size;
#endif /* AC_TWI_SLAVE_ENABLE */
#if AC_TWI_MASTER_ENABLE
    /** Current master status. */
    uint8_t master_current_status;
#endif /* AC_TWI_MASTER_ENABLE */
    /** Mex read message types. */
    uint8_t mex_read;
    /** Mex write message types. */
    uint8_t mex_write;
};

/** Global context. */
static struct twi_host_t twi_host_global;
#define ctx twi_host_global

#if AC_TWI_SLAVE_ENABLE

/** Handle READ requests from master. */
static void
twi_handle_READ (void *user, mex_msg_t *msg);

/** Handle WRITE requests from master. */
static void
twi_handle_WRITE (void *user, mex_msg_t *msg);

#endif /* AC_TWI_SLAVE_ENABLE */

void
twi_init (uint8_t addr)
{
    const char *mex_instance;
    assert ((addr & 1) == 0);
    ctx.address = addr;
    mex_instance = host_get_instance ("global", 1);
    ctx.mex_read = mex_node_reservef ("%s:read", mex_instance);
    ctx.mex_write = mex_node_reservef ("%s:write", mex_instance);
#if AC_TWI_SLAVE_ENABLE
    ctx.slave_send_buffer_size = 1;
    ctx.slave_send_buffer[0] = 0;
    mex_node_register (ctx.mex_read, twi_handle_READ, NULL);
    mex_node_register (ctx.mex_write, twi_handle_WRITE, NULL);
#endif /* AC_TWI_SLAVE_ENABLE */
#if AC_TWI_MASTER_ENABLE
    ctx.master_current_status = TWI_MASTER_ERROR;
#endif /* AC_TWI_MASTER_ENABLE */
}

void
twi_uninit (void)
{
    ctx.address = 0xff;
}

#if AC_TWI_SLAVE_ENABLE

/** Update buffer to be sent to master if requested. */
void
twi_slave_update (const uint8_t *buffer, uint8_t size)
{
    assert (size && size <= AC_TWI_SLAVE_SEND_BUFFER_SIZE);
    memcpy (ctx.slave_send_buffer, buffer, size);
    ctx.slave_send_buffer_size = size;
}

/** Handle READ requests from master. */
static void
twi_handle_READ (void *user, mex_msg_t *msg)
{
    uint8_t addr, size;
    mex_msg_pop (msg, "BB", &addr, &size);
    if (addr == ctx.address)
      {
	assert (size <= AC_TWI_SLAVE_SEND_BUFFER_SIZE);
	mex_msg_t *m = mex_msg_new (ctx.mex_read);
	mex_msg_push_buffer (m, ctx.slave_send_buffer,
			     UTILS_MIN (size, ctx.slave_send_buffer_size));
	mex_node_response (m);
      }
}

/** Handle WRITE requests from master. */
static void
twi_handle_WRITE (void *user, mex_msg_t *msg)
{
    uint8_t addr, size;
    mex_msg_pop (msg, "B", &addr);
    if (addr == ctx.address)
      {
	size = mex_msg_len (msg);
	AC_TWI_SLAVE_RECV (mex_msg_pop_buffer (msg),
			   UTILS_MIN (size, AC_TWI_SLAVE_RECV_BUFFER_SIZE));
      }
}

#endif /* AC_TWI_SLAVE_ENABLE */

#if AC_TWI_MASTER_ENABLE

void
twi_master_send (uint8_t addr, const uint8_t *buffer, uint8_t size)
{
    /* Send message. */
    mex_msg_t *m = mex_msg_new (ctx.mex_write);
    mex_msg_push (m, "B", addr);
    mex_msg_push_buffer (m, buffer, size);
    mex_node_send (m);
    /* Update status, there is no background task. */
    ctx.master_current_status = size;
    /* If defined, call master done callback. */
#ifdef AC_TWI_MASTER_DONE
    AC_TWI_MASTER_DONE ();
#endif
}

void
twi_master_recv (uint8_t addr, uint8_t *buffer, uint8_t size)
{
    /* Send request and wait for response. */
    mex_msg_t *m = mex_msg_new (ctx.mex_read);
    mex_msg_push (m, "BB", addr, size);
    m = mex_node_request (m);
    int recv = mex_msg_len (m);
    assert (recv <= size);
    memcpy (buffer, mex_msg_pop_buffer (m), recv);
    /* Update status, there is no background task. */
    ctx.master_current_status = recv;
    /* If defined, call master done callback. */
#ifdef AC_TWI_MASTER_DONE
    AC_TWI_MASTER_DONE ();
#endif
}

uint8_t
twi_master_status (void)
{
    return ctx.master_current_status;
}

uint8_t
twi_master_wait (void)
{
    /* No background task, nothing to wait. */
    return ctx.master_current_status;
}

#endif /* AC_TWI_MASTER_ENABLE */

#if AC_TWI_NO_INTERRUPT

void
twi_update (void)
{
    /* Nothing to do. */
}

#endif /* AC_TWI_NO_INTERRUPT */