// // // apa.c // // asynchronous packet automata networking // // Neil Gershenfeld // // CBA MIT 12/4/11 // // (c) Massachusetts Institute of Technology 2011 // Permission granted for experimental and personal use; // license for commercial sale available from MIT. // // todo // flood route // rejected handshakes // bridge serial error checking // merge bridge port scan // adaptive bit timing // // // includes // #include // // functions // void apa_put_char(struct apa_port_type *port, char c, unsigned char *return_value) { // // put synchronous char on port with timeouts // // set ready // set(*port->port_out, port->pin_out); // // wait for start clock // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } // // set start bit // clear(*port->port_out, port->pin_out); // // bit 0 // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 0) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 1 // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 1) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 2 // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 2) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 3 // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 3) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 4 // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 4) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 5 // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 5) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 6 // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 6) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // bit 7 // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } if (((c >> 7) & 1) == 0) clear(*port->port_out, port->pin_out); else set(*port->port_out, port->pin_out); // // wait for stop clock // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } clear(*port->port_out, port->pin_out); bit_read_delay(); } void apa_get_char(struct apa_port_type *port, char *c, unsigned char *return_value) { // // read synchronous character on port with timeouts // *c = 0; // // wait for ready // *return_value = apa_timeout; while (1) { if (0 != pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } // // send start clock // set(*port->port_out, port->pin_out); // // wait for start bit // *return_value = apa_timeout; while (1) { if (0 == pin_test(*port->pins_in, port->pin_in)) break; *return_value -= 1; if (*return_value == 0) return; } // // bit 0 // clear(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 0); else *c |= (1 << 0); // // bit 1 // set(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 1); else *c |= (1 << 1); // // bit 2 // clear(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 2); else *c |= (1 << 2); // // bit 3 // set(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 3); else *c |= (1 << 3); // // bit 4 // clear(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 4); else *c |= (1 << 4); // // bit 5 // set(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 5); else *c |= (1 << 5); // // bit 6 // clear(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 6); else *c |= (1 << 6); // // bit 7 // set(*port->port_out, port->pin_out); bit_read_delay(); if (0 == pin_test(*port->pins_in, port->pin_in)) *c |= (0 << 7); else *c |= (1 << 7); // // stop clock // clear(*port->port_out, port->pin_out); bit_read_delay(); // // return // } void apa_get_packet(struct apa_port_type *port) { // // get packet on port with timeouts // char c; unsigned char return_value,count; // // find start // count = apa_timeout; do { apa_get_char(port, &c, &return_value); count -= 1; if ((return_value == 0) || (count == 0)) { port->path_in_length = 0; return; } } while (c != apa_start); // // get path // port->path_in_length = 0; count = apa_max_packet; do { apa_get_char(port, &c, &return_value); count -= 1; if ((return_value == 0) || (count == 0)) { port->path_in_length = 0; return; } port->path_in[port->path_in_length] = c; port->path_in_length += 1; } while (c != apa_divider); port->path_in_length -= 1; // // get payload // port->payload_in_length = 0; count = apa_max_packet; do { // // get next char // apa_get_char(port, &c, &return_value); count -= 1; if ((return_value == 0) || (count == 0)) { port->path_in_length = 0; return; } // // check for escape // if (c == apa_escape) { // // get escaped char // apa_get_char(port, &c, &return_value); count -= 1; if ((return_value == 0) || (count == 0)) { port->path_in_length = 0; return; } port->payload_in[port->payload_in_length] = c; port->payload_in_length += 1; // // get next char // apa_get_char(port, &c, &return_value); count -= 1; if ((return_value == 0) || (count == 0)) { port->path_in_length = 0; return; } } // // save char // port->payload_in[port->payload_in_length] = c; port->payload_in_length += 1; } while (c != apa_end); port->payload_in_length -= 1; } void apa_put_packet(struct apa_port_type *port) { // // put packet on port with timeouts // unsigned char i; char c; unsigned char return_value; // // put start // apa_put_char(port, apa_start, &return_value); if (return_value == 0) return; // // put path // for (i = 0; i < port->path_out_length; ++i) apa_put_char(port, port->path_out[i], &return_value); if (return_value == 0) return; port->path_out_length = 0; // // put divider // apa_put_char(port, apa_divider, &return_value); if (return_value == 0) return; // // put payload // for (i = 0; i < port->payload_out_length; ++i) { // // get next char // c = port->payload_out[i]; // // check if escape needed // if ((c == apa_end) || (c == apa_escape)) // // yes, put escape // apa_put_char(port, apa_escape, &return_value); if (return_value == 0) return; // // // put char // apa_put_char(port, c, &return_value); if (return_value == 0) return; } // // put end // apa_put_char(port, apa_end, &return_value); if (return_value == 0) return; // // success, clear packet and return // port->payload_out_length = 0; } void apa_move_packet(struct apa_port_type *port0, struct apa_port_type *port1) { // // move packet from port0 in to port1 out // unsigned char i; // // copy path // for (i = 0; i < port0->path_in_length; ++i) port1->path_out[i] = port0->path_in[i]; port1->path_out_length = port0->path_in_length; port0->path_in_length = 0; // // copy payload // for (i = 0; i < port0->payload_in_length; ++i) port1->payload_out[i] = port0->payload_in[i]; port1->payload_out_length = port0->payload_in_length; port0->payload_in_length = 0; } void apa_copy_packet(struct apa_port_type *port0, struct apa_port_type *port1) { // // copy packet from port0 in to port1 out // unsigned char i; // // copy path // for (i = 0; i < port0->path_in_length; ++i) port1->path_out[i] = port0->path_in[i]; port1->path_out_length = port0->path_in_length; // // copy payload // for (i = 0; i < port0->payload_in_length; ++i) port1->payload_out[i] = port0->payload_in[i]; port1->payload_out_length = port0->payload_in_length; } void apa_port_scan(struct apa_port_type *port) { // // port scan // struct apa_port_type *current_port; // // is an incoming packet waiting? // if (0 != pin_test(*port->pins_in, port->pin_in)) { // // yes, is the input empty? // if (port->path_in_length == 0) { // // yes, accept the packet // apa_get_packet(port); // // was a packet received? // if (port->path_in_length != 0) { // // yes, route it // apa_route_packet(port); } } // // no, reject it // } // // is an input packet waiting? // if (port->path_in_length != 0) { // // yes, is the destination here? // if (port->destination == apa_here) { // // yes, is the output empty? // if (port->path_out_length == 0) { // // yes, move packet to output, reverse path, and process // apa_move_packet(port,port); apa_reverse_path(port); apa_process_packet(port); } } // // destination not here, is it a flood? // else if (port->destination == apa_flood) { // // yes, copy to other ports // current_port = port->next_port; while (current_port->id != port->id) { apa_copy_packet(port,current_port); current_port = current_port->next_port; } port->path_in_length = 0; } // // destination not here or flood, loop over other ports // else { current_port = port->next_port; while (1) { // // is current port the destination? // if (port->destination == current_port->id) { // // yes, is current port empty? // if (current_port->path_out_length == 0) { // // yes, move packet to current port // apa_move_packet(port,current_port); break; } } // // no, back to same port? // if (port->id == current_port->id) { // // yes, discard invalid path // port->path_in_length = 0; } // // no, go to next port // current_port = current_port->next_port; } } } // // is an output packet waiting? // if (port->path_out_length != 0) { // // yes, try to send it // apa_put_packet(port); } } void apa_route_packet(struct apa_port_type *port) { // // route packet path and set destination // static unsigned char ptr; // // find pointer // ptr = 0; while (port->path_in[ptr] != apa_pointer) ++ptr; // // check if pointer reached divider // if ((ptr+1) == port->path_in_length) { // // yes, terminate // port->destination = apa_here; } else { // // no, transit // port->destination = port->path_in[ptr+1]; port->path_in[ptr] = port->id; port->path_in[ptr+1] = apa_pointer; } } void apa_reverse_path(struct apa_port_type *port) { // // reverse output packet path // static unsigned char i; static unsigned char temp[apa_max_packet]; for (i = 0; i < port->path_out_length; ++i) temp[i] = port->path_out[port->path_out_length-i-1]; for (i = 0; i < port->path_out_length; ++i) port->path_out[i] = temp[i]; } uint16_t apa_hex_int(unsigned char *ptr) { // // convert hex word to int // unsigned char hex_char(unsigned char arg) { if (('0' <= arg) && (arg <= '9')) return (arg - '0'); else if (('a' <= arg) && (arg <= 'f')) return (10 + arg - 'a'); else if (('A' <= arg) && (arg <= 'F')) return (10 + arg - 'A'); else return 0; } return ((hex_char(ptr[0]) << 12) + (hex_char(ptr[1]) << 8) + (hex_char(ptr[2]) << 4) + hex_char(ptr[3])); }