Skip to content

Commit af819bd

Browse files
committed
Initial commit
0 parents  commit af819bd

12 files changed

+759
-0
lines changed

.gitignore

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
*.lo
2+
*.la
3+
.libs
4+
acinclude.m4
5+
aclocal.m4
6+
autom4te.cache
7+
build
8+
config.guess
9+
config.h
10+
config.h.in
11+
config.log
12+
config.nice
13+
config.status
14+
config.sub
15+
configure
16+
configure.ac
17+
configure.in
18+
include
19+
install-sh
20+
libtool
21+
ltmain.sh
22+
Makefile
23+
Makefile.fragments
24+
Makefile.global
25+
Makefile.objects
26+
missing
27+
mkinstalldirs
28+
modules
29+
php_test_results_*.txt
30+
phpt.*
31+
run-test-info.php
32+
run-tests.php
33+
tests/**/*.diff
34+
tests/**/*.out
35+
tests/**/*.php
36+
tests/**/*.exp
37+
tests/**/*.log
38+
tests/**/*.sh
39+
tests/**/*.db
40+
tests/**/*.mem
41+
tmp-php.ini

canbus.c

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
/* canbus extension for PHP */
2+
3+
#ifdef HAVE_CONFIG_H
4+
# include "config.h"
5+
#endif
6+
7+
#include "php.h"
8+
#include "ext/standard/info.h"
9+
#include "php_canbus.h"
10+
#include "canbus_arginfo.h"
11+
12+
#include <linux/can/raw.h> //can_frame, masks
13+
#include <net/if.h> //ifreq
14+
#include <sys/ioctl.h> //ioctl, SIOCGIFINDEX
15+
#include <unistd.h> //read, close
16+
#include <fcntl.h> //fcntl
17+
18+
//Defines for easy class member access
19+
#define CANBUS_INTERFACE_P OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0)
20+
#define CANBUS_SOCKFD_P OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 1)
21+
22+
#define CANFRAME_ID_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 0)
23+
#define CANFRAME_LENGTH_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 1)
24+
#define CANFRAME_DATA_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 2 )
25+
26+
//Class entries
27+
zend_class_entry *canBus_ce = NULL;
28+
zend_class_entry *canFrame_ce = NULL;
29+
30+
/* {{{ CanBus constructor */
31+
PHP_METHOD(CanBus, __construct) {
32+
zend_string* interface;
33+
34+
//Parse arguments
35+
ZEND_PARSE_PARAMETERS_START(1, 1)
36+
Z_PARAM_STR(interface)
37+
ZEND_PARSE_PARAMETERS_END();
38+
39+
//Validate interface name
40+
if (ZSTR_LEN(interface) == 0) {
41+
php_error_docref(NULL, E_ERROR, "interface name cannot be empty");
42+
}
43+
44+
//Initialize $this->interface with provided name
45+
ZVAL_STR_COPY(CANBUS_INTERFACE_P, interface);
46+
}
47+
/* }}} */
48+
49+
/* {{{ CanBus init method */
50+
PHP_METHOD(CanBus, init) {
51+
zend_bool blocking = true;
52+
53+
//Parse arguments
54+
ZEND_PARSE_PARAMETERS_START(0, 1)
55+
Z_PARAM_OPTIONAL
56+
Z_PARAM_BOOL(blocking)
57+
ZEND_PARSE_PARAMETERS_END();
58+
59+
//If socket file descriptor is set, close it before another initialization
60+
zend_long sockFd = Z_LVAL_P(CANBUS_SOCKFD_P);
61+
if(sockFd != -1) {
62+
close(sockFd);
63+
}
64+
65+
//Open CAN network interface
66+
sockFd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
67+
if (sockFd == -1) {
68+
RETURN_FALSE;
69+
}
70+
71+
//Map CAN interface
72+
struct ifreq ifr;
73+
zval* interface = CANBUS_INTERFACE_P;
74+
strncpy(ifr.ifr_name, Z_STRVAL(*interface), IFNAMSIZ);
75+
if(ioctl(sockFd, SIOCGIFINDEX, &ifr) == -1) {
76+
RETURN_FALSE;
77+
}
78+
79+
//Bind the socket to the network interface
80+
struct sockaddr_can addr;
81+
addr.can_family = AF_CAN;
82+
addr.can_ifindex = ifr.ifr_ifindex;
83+
if(bind(sockFd, (struct sockaddr*)(&addr), sizeof(addr)) == -1) {
84+
RETURN_FALSE;
85+
}
86+
87+
//Conditionaly set socket to non-blocking mode
88+
if(!blocking) {
89+
90+
//Get flags
91+
int flags = fcntl(sockFd, F_GETFL, 0);
92+
if(flags == -1) {
93+
RETURN_FALSE;
94+
}
95+
96+
//Set non-blocking flag
97+
if (fcntl(sockFd, F_SETFL, flags | O_NONBLOCK) == -1) {
98+
RETURN_FALSE;
99+
}
100+
}
101+
102+
//Update $this->sockFd file descriptor
103+
ZVAL_LONG(CANBUS_SOCKFD_P, sockFd);
104+
105+
RETURN_TRUE;
106+
}
107+
/* }}} */
108+
109+
/* {{{ CanBus read single frame method */
110+
PHP_METHOD(CanBus, read) {
111+
struct can_frame canFrame;
112+
zend_long sockFd = Z_LVAL_P(CANBUS_SOCKFD_P);
113+
114+
//Try to read CAN frame
115+
ssize_t numBytes = read(sockFd, &canFrame, CAN_MTU);
116+
117+
//Return false if whole frame could not be read
118+
if(numBytes != CAN_MTU) {
119+
RETURN_FALSE;
120+
}
121+
122+
//Create CanFrame object
123+
zend_object *object = zend_objects_new(canFrame_ce);
124+
zval frame;
125+
ZVAL_OBJ(&frame, object);
126+
127+
//Initialize $frame->id
128+
ZVAL_LONG(CANFRAME_ID_P(&frame), canFrame.can_id);
129+
130+
//Initialize $frame->length
131+
ZVAL_LONG(CANFRAME_LENGTH_P(&frame), canFrame.can_dlc);
132+
133+
//Initialize $frame->data
134+
zval* data = CANFRAME_DATA_P(&frame);
135+
array_init_size(data, canFrame.can_dlc);
136+
137+
//fill $frame->data
138+
for(int i = 0; i < canFrame.can_dlc; i++) {
139+
add_next_index_long(data, canFrame.data[i]);
140+
}
141+
142+
//Return CanFrame
143+
RETURN_COPY(&frame);
144+
}
145+
/* }}} */
146+
147+
/* {{{ CanBus generate random frame */
148+
PHP_METHOD(CanBus, generateRandomFrame) {
149+
zend_object *object = zend_objects_new(canFrame_ce);
150+
151+
zval frame;
152+
ZVAL_OBJ(&frame, object);
153+
154+
//Generate random can_frame;
155+
struct can_frame canFrame;
156+
srand(time(NULL));
157+
canFrame.can_id = rand() % 0x7FF;
158+
canFrame.can_dlc = rand() % 8;
159+
for(int i = 0; i < canFrame.can_dlc; i++) {
160+
canFrame.data[i] = rand() % 0xFF;
161+
}
162+
163+
//Initialize $frame->id
164+
ZVAL_LONG(CANFRAME_ID_P(&frame), canFrame.can_id);
165+
166+
//Initialize $frame->length
167+
ZVAL_LONG(CANFRAME_LENGTH_P(&frame), canFrame.can_dlc);
168+
169+
//Initialize $frame->data
170+
zval* data = CANFRAME_DATA_P(&frame);
171+
array_init_size(data, canFrame.can_dlc);
172+
173+
//Fill $frame->data
174+
for(int i = 0; i < canFrame.can_dlc; i++) {
175+
add_next_index_long(data, canFrame.data[i]);
176+
}
177+
178+
//Return CanFrame
179+
RETURN_COPY(&frame);
180+
}
181+
/* }}} */
182+
183+
/* {{{ CanFrame constructor */
184+
PHP_METHOD(CanFrame, __construct) {
185+
zend_long id;
186+
HashTable* data;
187+
188+
//Parse arguments
189+
ZEND_PARSE_PARAMETERS_START(2, 2)
190+
Z_PARAM_LONG(id)
191+
Z_PARAM_ARRAY_HT(data)
192+
ZEND_PARSE_PARAMETERS_END();
193+
194+
//Validate provided ID with CAN 2.0B standard (0 to 2^31 - 1)
195+
if(id < 0 || id > 0x7FFFFFFF) {
196+
php_error_docref(NULL, E_ERROR, "parameter ID has to be in range of 0-0x7FFFFFFF");
197+
}
198+
199+
//Validate provided data has at most 8 elements
200+
zend_long dataLength = zend_hash_num_elements(data);
201+
if(dataLength > 8) {
202+
php_error_docref(NULL, E_ERROR, "data length has to be not greater than 8 elements");
203+
}
204+
205+
//Validate provided data constists only of zend_long in range of 0-255
206+
zval* temp;
207+
ZEND_HASH_FOREACH_VAL(data, temp) {
208+
//Validate type
209+
if(Z_TYPE_P(temp) != IS_LONG) {
210+
php_error_docref(NULL, E_ERROR, "data element has to be an int");
211+
continue;
212+
}
213+
214+
//Validate value
215+
zend_long value = Z_LVAL_P(temp);
216+
if(value < 0 || value > 0xFF) {
217+
php_error_docref(NULL, E_ERROR, "data element value has to be in range od 0-0xFF");
218+
}
219+
} ZEND_HASH_FOREACH_END();
220+
221+
//Initialize $this->id with provided id
222+
ZVAL_LONG(CANFRAME_ID_P(ZEND_THIS), id);
223+
224+
//Make copy of passed input data & initialize $this->data
225+
ZVAL_ARR(CANFRAME_DATA_P(ZEND_THIS), data);
226+
227+
//Initialize size of passed array
228+
ZVAL_LONG(CANFRAME_LENGTH_P(ZEND_THIS), dataLength);
229+
}
230+
/* }}} */
231+
232+
/* {{{ CanBus class registry */
233+
static zend_class_entry *register_class_CanBus(void) {
234+
zend_class_entry ce, *classEntry;
235+
236+
//Register class
237+
INIT_CLASS_ENTRY(ce, "CanBus", class_CanBus_methods);
238+
classEntry = zend_register_internal_class_ex(&ce, NULL);
239+
240+
//Register member: public string $id = undefined
241+
zval property_interface_default_value;
242+
ZVAL_UNDEF(&property_interface_default_value);
243+
zend_string *property_interface_name = zend_string_init("interface", strlen("interface"), true);
244+
zend_declare_typed_property(classEntry, property_interface_name, &property_interface_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
245+
zend_string_release(property_interface_name);
246+
247+
//Register member: protecte int $socketFd = -1
248+
zval property_socketFd_default_value;
249+
ZVAL_LONG(&property_socketFd_default_value, -1);
250+
zend_string *property_socketFd_name = zend_string_init("socketFd", strlen("socketFd"), true);
251+
252+
zend_declare_typed_property(classEntry, property_socketFd_name, &property_socketFd_default_value, ZEND_ACC_PROTECTED, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
253+
zend_string_release(property_socketFd_name);
254+
255+
return classEntry;
256+
}
257+
/* }}} */
258+
259+
/* {{{ CanFrame class registry */
260+
static zend_class_entry *register_class_CanFrame(void) {
261+
zend_class_entry ce, *classEntry;
262+
263+
//Register class
264+
INIT_CLASS_ENTRY(ce, "CanFrame", class_CanFrame_methods);
265+
classEntry = zend_register_internal_class(&ce);
266+
267+
//Register member: public int $id = 0
268+
zval id;
269+
ZVAL_LONG(&id, 0);
270+
zend_string *idName = zend_string_init("id", strlen("id"), true);
271+
zend_declare_typed_property(classEntry, idName, &id, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
272+
zend_string_release(idName);
273+
274+
//Register member: public int $length = 0
275+
zval length;
276+
ZVAL_LONG(&length, 0);
277+
zend_string *lengthName = zend_string_init("length", strlen("length"), true);
278+
zend_declare_typed_property(classEntry, lengthName, &length, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
279+
zend_string_release(lengthName);
280+
281+
//Register member: public array $data = []
282+
zval data;
283+
ZVAL_EMPTY_ARRAY(&data);
284+
zend_string *dataName = zend_string_init("data", strlen("data"), true);
285+
zend_declare_typed_property(classEntry, dataName, &data, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY));
286+
zend_string_release(dataName);
287+
288+
return classEntry;
289+
}
290+
/* }}} */
291+
292+
/* {{{ PHP_RINIT_FUNCTION */
293+
PHP_RINIT_FUNCTION(canbus){
294+
#if defined(ZTS) && defined(COMPILE_DL_CANBUS)
295+
ZEND_TSRMLS_CACHE_UPDATE();
296+
#endif
297+
298+
return SUCCESS;
299+
}
300+
/* }}} */
301+
302+
/*{{{ PHP_MINIT_FUNCTION */
303+
PHP_MINIT_FUNCTION(canbus) {
304+
canBus_ce = register_class_CanBus();
305+
canFrame_ce = register_class_CanFrame();
306+
307+
return SUCCESS;
308+
}
309+
/* }}} */
310+
311+
/* {{{ PHP_MINFO_FUNCTION */
312+
PHP_MINFO_FUNCTION(canbus) {
313+
php_info_print_table_start();
314+
php_info_print_table_header(2, "canbus support", "enabled");
315+
php_info_print_table_end();
316+
}
317+
/* }}} */
318+
319+
/* {{{ canbus_module_entry */
320+
zend_module_entry canbus_module_entry = {
321+
STANDARD_MODULE_HEADER,
322+
"canbus", /* Extension name */
323+
NULL, /* zend_function_entry */
324+
PHP_MINIT(canbus), /* PHP_MINIT - Module initialization */
325+
NULL, /* PHP_MSHUTDOWN - Module shutdown */
326+
PHP_RINIT(canbus), /* PHP_RINIT - Request initialization */
327+
NULL, /* PHP_RSHUTDOWN - Request shutdown */
328+
PHP_MINFO(canbus), /* PHP_MINFO - Module info */
329+
PHP_CANBUS_VERSION, /* Version */
330+
STANDARD_MODULE_PROPERTIES
331+
};
332+
/* }}} */
333+
334+
#ifdef COMPILE_DL_CANBUS
335+
# ifdef ZTS
336+
ZEND_TSRMLS_CACHE_DEFINE()
337+
# endif
338+
339+
ZEND_GET_MODULE(canbus)
340+
#endif

0 commit comments

Comments
 (0)