home *** CD-ROM | disk | FTP | other *** search
- /*****
- *
- * File: cm_cellsim.c
- *
- * Cellsim, cellular automata simulator
- *
- * Routines to communicate with the Connection Machine Front End (CMFE),
- * and maintain data-structures relevant to controlling the CM.
- *
- *****/
-
-
-
- #include "cm_cellsim.h"
-
-
- /*
- *
- * Cellsim copyright 1989, 1990 by Chris Langton and Dave Hiebeler
- * (cgl@lanl.gov, hiebeler@heretic.lanl.gov)
- *
- * This package may be freely distributed, as long as you don't:
- * - remove this notice
- * - try to make money by doing so
- * - prevent others from copying it freely
- * - distribute modified versions without clearly documenting your changes
- * and notifying us
- *
- * Please contact either of the authors listed above if you have questions
- * or feel an exception to any of the above restrictions is in order.
- *
- * If you make changes to the code, or have suggestions for changes,
- * let us know! If we use your suggestion, you will receive full credit
- * of course.
- */
-
- /*****
- * Cellsim history:
- *
- * Cellsim was originally written on Apollo workstations by Chris Langton.
- *
- * Sun versions:
- *
- * - version 1.0
- * by C. Ferenbaugh and C. Langton
- * released 09/02/88
- *
- * - version 1.5
- * by Dave Hiebeler and C. Langton May - June 1989
- * released 07/03/89
- *
- * - version 2.0
- * by Dave Hiebeler and C. Langton July - August 1989
- * never officially released (unofficially released 09/08/89)
- *
- * - version 2.5
- * by Dave Hiebeler and C. Langton September '89 - February 1990
- * released 02/26/90
- *****/
-
-
- /*
- * wait for acknowledgement from CMFE, and an error msg if something
- * went wrong
- */
- int
- CM_wait_for_ack()
- {
- unsigned char buf[80];
-
- clear_msg();
- show_msg("Waiting for CM...");
- read_from_sock(server_fd, buf, 1, OFF, 0);
- clear_msg();
- if (buf[0] == 0) {
- show_msg("CM program crashed...");
- sleep(1);
- fprintf(stderr, "CM program has crashed...\n");
- CM_disconnect();
- return 1;
- }
- if (buf[0] != DONE) {
- read_from_sock(server_fd, buf, 80, OFF, 0);
- show_msg("Error on CM");
- show_msg(buf);
- return 1;
- }
- else
- show_msg("Done.");
- return 0;
- }
-
-
- /*
- * Send a byte to the CMFE
- */
- void
- CM_send_byte(b)
- unsigned char b;
- {
- unsigned char local_b;
-
- local_b = b;
- write_to_sock(server_fd, &local_b, 1, OFF, 0);
- }
-
-
- /*
- * Send integer to CMFE. This has to be done this way, rather than
- * just sending it directly, because a Vax holds its integers with bytes
- * in reverse order relative to Suns. So a portable method was needed.
- */
- void
- CM_send_int(n)
- int n;
- {
- unsigned char buf[4];
-
- /* buf[0] = n%256;
- buf[1] = n/256;
- buf[2] = n/(256*256);
- buf[3] = n/(256*256*256);
- */
- buf[0] = n & 0xff;
- buf[1] = (n>>8) & 0xff;
- buf[2] = (n>>16) & 0xff;
- buf[3] = (n>>24) & 0xff;
- write_to_sock(server_fd, buf, 4, OFF, 0);
- }
-
-
- /*
- * Read an int from CMFE.
- */
- int
- CM_read_int()
- {
- unsigned char buf[4];
- int n;
-
- read_from_sock(server_fd, buf, 4, OFF, 0);
- n = buf[0] + buf[1]*256;
- n += buf[2]*256*256 + buf[3]*256*256*256;
- return n;
- }
-
-
- /*
- * Connect to a waiting socket on a CMFE
- */
- void
- CM_connect()
- {
- char buf[80], nh[80];
- struct hostent *server_hostent;
- int tmp, err, use_host_number;
- long int CM_host;
- struct in_addr tmp_addr;
-
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (setting_sequence)
- add_sequence(CM_connect);
- if (use_CM) {
- show_msg("Already connected to CM");
- return;
- }
- if (!valid_CM_state(NHOOD, S, R)) {
- show_msg("Invalid nhood for use");
- show_msg("with CM");
- return;
- }
- if (!valid_CM_image(B)) {
- show_msg("Image size must be 128 or");
- show_msg("256 or 512 to connect to CM");
- return;
- }
- def_CM_get_settings();
- switch (B) {
- case 128:
- CM_zoom = 6;
- break;
- case 256:
- CM_zoom = 3;
- break;
- case 512:
- CM_zoom = 1;
- break;
- }
- CM_panx = B/2;
- CM_pany = B/2;
- set_CM_sliders();
- err = sscanf(CM_hostname, "%d", &tmp);
- if ((err == 0) || (tmp == 0))
- use_host_number = 0;
- else
- use_host_number = 1;
- if (use_host_number)
- CM_host = inet_addr(CM_hostname);
- else
- {
- if ((server_hostent = gethostbyname(CM_hostname)) == NULL) {
- sprintf(buf,"Host '%s' unknown",CM_hostname);
- clear_msg();
- show_msg(buf);
- return;
- }
- CM_host = *((long int *) server_hostent->h_addr);
- }
- tmp_addr.s_addr = CM_host;
- sprintf(buf, "Trying to connect");
- show_msg(buf);
- sprintf(buf, "to %s", inet_ntoa(tmp_addr));
- show_msg(buf);
- if ((server_fd = connect_to_waiting_socket(CM_host, CM_port, 0)) == -1) {
- sprintf(buf, "Error trying to connect");
- show_msg(buf);
- return;
- }
- clear_msg();
- show_msg("Successfully connected");
- use_CM = 1;
- read_from_sock(server_fd, buf, 1, OFF, 0); /* read 1 byte to be sure
- * someone's really there */
- /* Construct a string to tell CMFE what nhood and size to use */
- switch (NHOOD) {
- case NH_VONN:
- nh[0] = 'v';
- break;
- case NH_MOORE:
- nh[0] = 'm';
- break;
- case NH_MARG:
- nh[0] = 'M';
- break;
- case NH_LIN:
- nh[0] = 'l';
- break;
- }
- sprintf(&nh[1], "%d ", S);
- strcpy(buf, nh);
- sprintf(&buf[strlen(buf)], "b%d", B);
- if (NHOOD == NH_LIN)
- sprintf(&buf[strlen(buf)], " r%d", R);
- write_to_sock(server_fd, buf, 80, OFF, 0);
- /* set up some intiial stuff on the CM */
- if (SOCKET_INUSE)
- CM_send_byte(USE_SOCK);
- else
- CM_send_byte(DONT_USE_SOCK);
- CM_set_displays();
- CM_set_disp_interval();
- CM_send_cmap();
- CM_send_delay();
- CM_send_zoom();
- CM_send_pan();
- CM_get_dirs();
- /* It's possible something bombed on the CMFE while we were doing this,
- * so let's make a final check */
- if (use_CM)
- show_msg("Connected to CM");
- else
- show_msg("Not connected!");
- }
-
-
- /*
- * See if we're connected to CMFE. If err is non-zero, print a message
- * complaining if we're not connected. Otherwise, silently return 1 if
- * we are NOT connected, 0 if we are connected.
- */
- int
- CM_check_connection(err)
- int err;
- {
- if (!use_CM) {
- if (err) {
- clear_msg();
- show_msg("Not connected to CM");
- }
- return 1;
- }
- return 0;
- }
-
-
-
- /*
- * Run for specified # of steps on CM
- */
- void
- CM_auto_step(step)
- int step;
- {
- CM_auto_screen(step);
- }
-
-
-
- void
- CM_auto_screen(step)
- int step;
- {
- char buf[80];
- int i,j;
-
- if (CM_check_connection(1))
- return;
- CM_send_delay();
- CM_send_byte(RUN); /* tell CMFE we want to run */
- CM_send_int(step); /* and how long to run */
- CM_send_int(CM_disp_interval); /* and how often to display */
- if (function) { /* send parms if necessary */
- CM_send_int(parm1);
- CM_send_int(parm2);
- }
- if (NHOOD == NH_MARG) { /* and stime for margolus phase */
- CM_send_int(stime);
- }
- /* read back state-counts, if that is being done */
- if (SOCKET_INUSE) {
- for (i=0; i<step; i++) {
- read_from_sock(server_fd, buf, S*4, OFF, 0);
- for (j=0; j<S; j++)
- statecount[j] = buf[j*4] + buf[j*4 + 1]*256 +
- buf[j*4 + 2]*256*256 + buf[j*4 + 3]*256*256*256;
- send_sock();
- }
- }
- CM_wait_for_ack(); /* get acknowledgement from CMFE */
- clear_msg();
- show_msg("Done");
- }
-
-
- /*
- * This routine is used to "run forever", that is run with no bound.
- * It's different than above, because the CM will have to check the
- * socket every now & then to see if the Sun has told it to stop.
- */
- void
- CM_auto_run()
- {
- if (CM_check_connection(1))
- return;
- CM_send_delay();
- CM_send_byte(RUN_FOREVER); /* tell CMFE we want to run forever */
- if (function) {
- CM_send_int(parm1);
- CM_send_int(parm2);
- }
- if (NHOOD == NH_MARG) {
- CM_send_int(stime);
- }
- CM_send_int(CM_disp_interval);
- /* Now that we've sent all the necessary parms, just return.
- * The routine that called this one will tell the CM when to stop.
- */
- clear_msg();
- show_msg("Done.");
- }
-
-
- /*
- * This routine sends a byte to the CM to terminate a "forever run".
- */
- void
- CM_stop_run()
- {
- CM_send_byte(STOP_RUN);
- /* Find out how long CM ran, and increment time-variable */
- stime += CM_read_int();
- }
-
-
- /*
- * Send lookup table to CM
- */
- void
- CM_send_LT()
- {
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (function) {
- show_msg("Can't send LT when");
- show_msg("using 256 states");
- }
- if (setting_sequence)
- add_sequence(CM_send_LT);
- if (CM_check_connection(1))
- return;
- CM_send_byte(SEND_LT);
- CM_send_byte(UNCOMPRESSED); /* future versions may be able to send
- * things in compressed form... */
- show_msg("Sending LT...");
- write_to_sock(server_fd, ta, TSIZE, OFF, 0);
- CM_wait_for_ack();
- }
-
-
-
- /*
- * Send colormap to CM, for use on the CM Frame Buffer (CMFB)
- */
- void
- CM_send_cmap()
- {
- unsigned char red[256], green[256], blue[256];
-
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (setting_sequence)
- add_sequence(CM_send_cmap);
- if (CM_check_connection(1))
- return;
- CM_send_byte(SEND_CMAP);
- set_rgb_arrays(red,green,blue); /* get cmap into rgb arrays */
- /* Now send arrays */
- write_to_sock(server_fd, red, 256, OFF, 0);
- write_to_sock(server_fd, green, 256, OFF, 0);
- write_to_sock(server_fd, blue, 256, OFF, 0);
- CM_wait_for_ack();
- }
-
-
- /*
- * Send current image over to CM
- */
- void
- CM_send_image()
- {
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (setting_sequence)
- add_sequence(CM_send_image);
- if (CM_check_connection(1))
- return;
- CM_send_byte(SEND_IMAGE);
- CM_send_byte(UNCOMPRESSED);
- show_msg("Sending image...");
- /* Note that we send the whole 2-D array, even when using 1-D nhood */
- write_to_sock(server_fd, ca + B, B*B, OFF, 0);
- CM_wait_for_ack();
- }
-
-
- /*
- * Probe on CM. Right now, this really uses the CM to probe a local
- * neighborhood, rather than probing the neighborhood at the selected
- * coordinates on the CM
- */
- int
- CM_probe(x,y,a)
- int x,y,a; /* table address */
- {
- char buf[128];
-
- clear_msg();
- if (CM_check_connection(1))
- return;
- if (function) {
- show_msg("Can't probe on CM in");
- show_msg("256-state mode yet");
- return;
- }
- CM_send_byte(PROBE);
- CM_send_int(x);
- CM_send_int(y);
- bcopy(&a, buf, 4);
- write_to_sock(server_fd, buf, 4, OFF, 0);
- if (NHOOD == NH_MARG) {
- CM_send_int(stime);
- }
- /* read back results */
- read_from_sock(server_fd, buf, 1, OFF, 0);
- return (int)buf[0];
- }
-
-
- /*
- * Display the image currently in memory on the CM.
- * This involves either or both of:
- * - displaying the image on the CM frame-buffer, if it exists and has
- * been enabled
- * - reading the image back to the Sun through the socket, and
- * displaying it in the Cellsim canvas.
- */
- void
- CM_display_image()
- {
- if (CM_check_connection(1))
- return;
- CM_send_byte(DISPLAY);
- if (use_Sun_disp) {
- swap_data();
- clear_msg();
- show_msg("Reading image from CM..");
- CM_send_byte(UNCOMPRESSED);
- read_from_sock(server_fd, ca + B, B*B, OFF, 0);
- show_msg("Done.");
- display_image();
- }
- }
-
-
- /*
- * Disconnect from the CMFE
- */
- void
- CM_disconnect()
- {
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (setting_sequence)
- add_sequence(CM_disconnect);
- if (CM_check_connection(1))
- return;
- CM_send_byte(QUIT);
- close(server_fd);
- use_CM = 0;
- show_msg("Disconnected from CM.");
- }
-
-
- void
- CM_change_stuff(str)
- char *str;
- {
- char buf[80];
-
- CM_send_byte(CHANGE_STUFF);
- /* "str" might not be 80 chars long, so make a local copy to send */
- strcpy(buf, str);
- write_to_sock(server_fd, buf, 80, OFF, 0);
- CM_wait_for_ack();
- }
-
-
-
- /*
- * Send run-delay to CMFE
- */
- void
- CM_send_delay()
- {
- if (CM_check_connection(0))
- return;
- CM_send_byte(CHANGE_DELAY);
- CM_send_int(CM_delay);
- CM_wait_for_ack();
- }
-
-
- /*
- * Tell CMFE which displays (CMFB and/or Sun display) we want to use
- */
- void
- CM_set_displays()
- {
- byte setting;
-
- setting = use_FB + use_Sun_disp * 2;
- if (CM_check_connection(0))
- return;
- CM_send_byte(SET_DISPLAYS);
- CM_send_byte(setting);
- CM_wait_for_ack();
- }
-
-
- /*
- * Set display-interval for displaying images when running
- */
- void
- CM_set_disp_interval()
- {
- if (CM_check_connection(0))
- return;
- CM_send_byte(SET_DISP_INTERVAL);
- CM_send_int(CM_disp_interval);
- CM_wait_for_ack();
- }
-
-
- /*
- * Load an image into CM array, from the CMFE filesystem
- */
- void
- CM_load_image(fname)
- char fname[128];
- {
- if (CM_check_connection(1))
- return;
- CM_send_byte(LOAD_IMAGE);
- write_to_sock(server_fd, fname, 128, OFF, 0);
- CM_wait_for_ack();
- }
-
-
- /*
- * Generate a quick random image on CM
- */
- CM_quick_random()
- {
- if (CM_check_connection(1))
- return;
- CM_send_byte(QUICK_RANDOM);
- CM_wait_for_ack();
- }
-
-
- /*
- * Generate general random image on CM
- */
- CM_general_random()
- {
- if (CM_check_connection(1))
- return;
- CM_send_byte(GENERAL_RANDOM);
- CM_send_int(saved_ox);
- CM_send_int(saved_oy);
- CM_send_int(saved_sx);
- CM_send_int(saved_sy);
- CM_send_int(saved_density);
- CM_send_int(saved_min_val);
- CM_send_int(saved_max_val);
- CM_wait_for_ack();
- }
-
-
- /*
- * Clear array on CM
- */
- CM_clear()
- {
- if (CM_check_connection(1))
- return;
- CM_send_byte(CLEAR);
- CM_wait_for_ack();
- }
-
-
- /*
- * Get image from CM to local array
- */
- CM_get_image_proc()
- {
- if (CM_check_connection(1))
- return;
- clear_msg();
- show_msg("Reading image from CM..");
- CM_send_byte(GET_IMAGE);
- read_from_sock(server_fd, ca + B, B*B, OFF, 0);
- display_image();
- show_msg("Done.");
- }
-
-
-
- /*
- * Get image-dir from CMFE
- */
- CM_get_image_dir()
- {
- char buf[128];
-
- CM_send_byte(GET_CM_IMAGE_DIR);
- read_from_sock(server_fd, buf, 128, OFF, 0);
- strcpy(CM_image_dir, buf);
- }
-
-
- /*
- * Send image-dir to CMFE
- */
- CM_send_image_dir()
- {
- if (CM_check_connection(1))
- return;
- clear_msg();
- CM_send_byte(SET_CM_IMAGE_DIR);
- write_to_sock(server_fd, CM_image_dir, 128, OFF, 0);
- }
-
-
-
-
- /*
- * Get fcn-dir from CMFE
- */
- CM_get_fcn_dir()
- {
- char buf[128];
-
- CM_send_byte(GET_CM_FCN_DIR);
- read_from_sock(server_fd, buf, 128, OFF, 0);
- strcpy(CM_fcn_dir, buf);
- }
-
-
- /*
- * Send fcn-dir to CMFE
- */
- CM_send_fcn_dir()
- {
- if (CM_check_connection(1))
- return;
- clear_msg();
- CM_send_byte(SET_CM_FCN_DIR);
- write_to_sock(server_fd, CM_fcn_dir, 128, OFF, 0);
- }
-
-
-
- /*
- * Get LT-dir from CMFE
- */
- CM_get_LT_dir()
- {
- char buf[128];
-
- CM_send_byte(GET_CM_LT_DIR);
- read_from_sock(server_fd, buf, 128, OFF, 0);
- strcpy(CM_LT_dir, buf);
- }
-
-
- /*
- * Send LT-dir to CMFE
- */
- CM_send_LT_dir()
- {
- if (CM_check_connection(1))
- return;
- clear_msg();
- CM_send_byte(SET_CM_LT_DIR);
- write_to_sock(server_fd, CM_LT_dir, 128, OFF, 0);
- }
-
-
-
- /*
- * Load a rule (either LT or fcn) from CMFE filesystem
- */
- CM_load_rule_proc()
- {
- char fname[128], buf[128];
-
- if (CM_check_connection(1))
- return;
- clear_msg();
- if (invalid_set_pressed())
- return;
- if (setting_sequence)
- add_sequence(CM_load_rule_proc);
- def_CM_get_settings();
- get_msg("Load CM rule:", buf, BUFLEN, saved_CM_rule_file);
- if (buf[0] == NULL)
- return;
- strcpy(saved_CM_rule_file, buf);
- strcpy(fname, buf);
- if (auto_nhood_change)
- change_stuff_file(buf);
- strcpy(buf, fname);
- CM_send_byte(LOAD_RULE);
- write_to_sock(server_fd, fname, 128, OFF, 0);
- if (CM_wait_for_ack())
- return;
- if (function) {
- parm1 = CM_read_int();
- parm2 = CM_read_int();
- }
- }
-
-
- /*
- * Set the zoom-factor (magnification) of CM Frame Buffer (CMFB)
- */
- CM_set_zoom()
- {
- int new_zoom;
-
- clear_msg();
- if (get_num("New zoom factor: ", &new_zoom, 0, 1000000, CM_zoom))
- return;
- CM_zoom = new_zoom;
- CM_send_zoom();
- }
-
-
- /*
- * Send the new zoom-factor to CMFE
- */
- CM_send_zoom()
- {
- CM_send_byte(SET_ZOOM);
- CM_send_int(CM_zoom);
- /* CM_wait_for_ack(); */
- }
-
-
-
- /*
- * Send pan (translational offsets) for CMFB image
- */
- CM_send_pan()
- {
- CM_panx = CM_panx - CM_panx%8;
- CM_pany = CM_pany - CM_pany%4;
- CM_send_byte(SET_PAN);
- CM_send_int(CM_panx);
- CM_send_int(CM_pany);
- /* CM_wait_for_ack(); */
- }
-
-
- /*
- * Tell CMFE we've changed image-size
- */
- CM_change_image_size()
- {
- CM_send_byte(CHANGE_IMAGE_SIZE);
- CM_send_int(B);
- CM_wait_for_ack();
- /* Reset the zoom factor to be something good again */
- if (B == 128)
- CM_zoom = 6;
- else if (B == 256)
- CM_zoom = 3;
- else if (B == 512)
- CM_zoom = 1;
- CM_panx = B/2;
- CM_pany = B/2;
- set_CM_sliders();
- CM_send_zoom();
- }
-
-
- void
- CM_send_dirs()
- {
- CM_send_LT_dir();
- CM_send_fcn_dir();
- CM_send_image_dir();
- }
-