SYSTEM AND METHOD FOR MONITORING AND CONTROLLING ENERGY DISTRIBUTION

Abstract: A system (2) that monitors and controls energy distribution manages energy distribution or use for Energy Service Providers (8) and end-users (6). The system includes a publicly or privately acessible distributed network (16), a network access device (4) and a management device (10). The network access device (4) communicates with the management device (10) through the distributed network (16) to control loads at a remote location. The method of monitoring and controlling energy distribution receives data at an on-line site, processes an application program that evaluates load and market supply data, and initiates power curtailment requests or power curtailment events.

Description: SYSTEM AND METHOD FOR MONITORING AND CONTROLLING ENERGY DISTRIBUTION MICROFICHE APPENDIX A Microfiche Appendix of the presently preferred source code is attached and comprises two (2) sheets having a total of 168 frames (98 on frame 1 and 70 on frame two). The Microfiche Appendix contains material that is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction of the Microfiche Appendix as it appears in the Patent and Trademark Office patent files or records, but otherwise reserves all copyright rights whatsoever. BACKGROUND 1. Technical Field The present invention relates to a system and a method that manages energy use, and in particular, to a system and a method that monitors energy use and energy supplies using either a public or a private distributed network to initiate curtailment requests and disconnect dispensable loads from energy supplies or activate end-user generators. 2. Description of Related Art New supplies of electricity will be needed as demand for electricity grows. To meet this demand, local and regional utilities are evaluating many different strategies from the building of thermal (steam-generated), water powered, fossil fuel, and nuclear generators to the pooling of unutilized electric capacity. In pooling systems, utilities join together in a grid system to share and distribute unutilized electric capacity through open market allocations. These systems offer great opportunities for economic gain as electric demand can be met without substantial investments in new power plants. However, these systems also have risks. Grid systems can breakdown when demand exceeds supply, which can affect large numbers of end users. To protect against power failures, end-users must also improve end-use efficiency. One means of achieving a sustainable supply of electric power in the future is to use efficient end-use technologies. Energy efficiency programs that focused only on appliances, power plants, and equipment in the past now need to pursue other avenues of technology that increase the availability of energy and improve supply and end-user efficiency. New technologies must be found to meet customer, generator, supplier, network operator, regulator, and environmental policy maker objectives. Another means of achieving a sustainable supply of electric power is to create competitive electric markets driven by demand side bidding. The goal of demand side bidding is to reduce the demand for energy through efficient load utilization and efficient energy distribution. Demand side bidding offsets the need for increased generation through demand reduction. The system treats an offer from an end-user to reduce demand as an offer to sell generated electricity. The energy not consumed by an end-user is considered "generated" as it is available to meet other demand. There can be contractual incentives for end-users to switch dispensable loads off-line during periods of high demand. End-users, for example, might receive payments for "generating" electricity they do not consume. In practice, such a system has not met expectations as it requires an accessible system that integrates open market price exchanges with advanced technology. BRIEF DESCRIPTION OF THE DRAWINGS FIG. 1 is a block diagram of a first embodiment of the invention. FIG. 2 is a block diagram of an Internet Customer Curtailment Module device of FIG. 1. FIG. 3 is a block diagram of a Command and Control Center of FIG. 1. FIG. 4 is a block diagram of the Command and Control Center of FIG. 1. FIG. 5 is a block diagram of the Command and Control Center of FIG. 1. FIG. 6 is a flow-chart of the Energy1st-2000 of FIG. 2. FIG. 7 is a block diagram of an on-line Site of FIG. 1. FIG. 8 is an exemplary start-page of the on-line Site of FIG. 1. FIG. 9 is an exemplary address dialog-box of FIG. 1. FIG. 10 is an exemplary contact dialog-box of FIG. 1. FIG. 11 is an exemplary load summary dialog-box of FIG. 1. FIG. 12 is an exemplary option dialog-box of FIG. 1. FIG. 13 is an exemplary forecast dialog box of FIG. 1. FIG. 14 is an exemplary communication summary of FIG. 1. FIG. 15 is an exemplary Energy1st-2000 dialog-box of FIG. 1 illustrating a HVAC interface assigned to an exemplary zone and exemplary meter summaries. FIG. 16 is an exemplary log of the exemplary zone of FIG. 15. FIG. 17 is an exemplary Energy1st-2000 dialog box of FIG. 1 assigned to an exemplary zone. FIG. 18 is an exemplary Watermark dialog-box of the exemplary zone of FIG. 17. FIG. 19 is an exemplary application function of FIG. 1. FIG. 20 is an exemplary start-page dialog box of the curtailment system of FIG. 1. FIG. 21 is an exemplary application function of FIG. 20. FIG. 22 is an exemplary message initiation and automated load management function of FIG. 20. FIG. 23 is an exemplary curtailment notification/acknowledgement status summary of FIG. 20. FIG. 24 is an exemplary user-defined graphic of FIG. 1. In the drawings, the same reference numbers through several views designate the same or similar elements. DETAILED DESCRIPTION The system and method of the present invention overcomes many barriers to a successful demand side bidding program by integrating open market energy price exchanges with advanced communication, database, and curtailment technologies. The system and method of the invention provides complete access to real-time load profiles and load control data and provides end-users, such as end-user customers, and energy supply providers with manual, automatic, and hybrid control of load reduction processes that optimize energy distribution and energy use. Energy supply providers include energy marketers, grid owners, utilities, merchant plant proprietors, cooperatives, and municipalities. FIG. 1 illustrates a block diagram of a preferred embodiment of the invention. The system 2 preferably comprises a network access device such as an Energyl st-2000 ("E1 -2000") , 4, a customer or end-user interface 6, an Energy Service Provider ("ESP") interface 8, and a management device 10. The network access device, customer or end-user interface 6, ESP interface 8, and management device 10 are preferably joined together by gateways linked together by a publicly accessible or a privately accessible distributed network. The gateways perform protocol conversions, data translations, data conversions, and message handling. Preferably, an access provider, such as an Internet Service Provider ("ISP") 12, provides network connectivity services to the network access device, the customer or end-user interface 6, the ESP interface 8, and the management device 10. Connectivity can be provided in many ways. One way allows devices to dial up the access provider through a modem. A modem, which is any device that converts data from one form to another, uses landlines or wireless transceivers to access remote devices. Connectivity can also be achieved through dedicated lines such as T1 carriers. T1 carriers are private lines or leased lines unlike the public lines or switched lines used in standard dial-up telephone connections. T1 carriers provide high bandwidths that can transmit large blocks of text and image data. A third means of connectivity uses set-top boxes that uses communication and signal-routing technology to access publicly accessible networks, such as the Internet 16 through coaxial, fiber optic, twisted pair, or other types of cable. A network access device is a controller and its supporting interfaces that coordinates communication and control between power monitoring circuitry, power curtailment circuitry, and a distributed network. A preferred embodiment of a network access device is an E1-2000 4 that links power monitoring circuitry 14, power curtailment circuitry, and a management device 10 through a publicly accessible distributed network such as the Internet 16, for example. An E1-2000 4 accepts structured input; processes it according to a set of prescribed rules, and produces outputs. Some outputs are sent to the management device 10 through the ISP 12. In the preferred embodiment, the E1-2000 4 comprises a processor, a nonvolatile or FLASH memory, two RS-232-C asynchronous serial communication ports, one RS-232-C / RS-485 asynchronous serial communication port, a modem, a Local Area Network ("LAN") device, such as an Ethernet device or LAN that utilizes Carrier Senses with Multiple Access Collision Detection ("CSMA CD") protocol to regulate communication line traffic, three relay controlled ("digital") and two analog voltage channels, an eight channel pulse accumulator device, a push button-switch card with an interface, a visual ("a light") and/or auditory ("piezoelectric transducer") alarm and a 60W/110V power supply. The E1-2000 4 operates under the control of a processor that provides a platform to execute application programs. The non-volatile or Flash memory stores code and data on a temporary ("volatile") and on a permanent ("non-volatile") basis. Unlike some non-volatile memory that is erased and programmed in bytes, the FLASH memory is erased and programmed in blocks and in some preferred embodiments can interface five volt, three volt, and two volt system buses. In one preferred embodiment, the FLASH memory performs reading and programming operations simultaneously. Preferably, two RS-232-C asynchronous serial communication ports provide point-to-point serial communication between peripheral devices. The RS-232-C / RS-485 serial communication port allows multiple meters, pulse accumulators 18, device control and building control systems, counters, and displays to be connected to the same RS-232-C / RS-485 line in parallel. Because each of these devices has its own unique digital address, the RS-232-C / RS-485 port can support up to 254 digital addresses that allows multiple devices to be addressed and transmit on the same communication line. An internal modem and Ethernet device allows the E1-2000 4 to communicate with an access provider such as an ISP 12 or other network nodes at a prescribed programmable frequency of seconds, minutes, weeks, months or other desired time increments. The modem and Ethernet device can communicate to devices dispersed across local or distant areas. Preferably, three relay controlled voltage channels or digital channels and two analog voltage channels interface external devices such as dispensable loads or generators. The three relay controlled and two analog voltage channels can control power generators and/or Heating Ventilation and Air Controllers ("HVAC"), lighting controls, motors, boilers, and cooler loads and/or other facility control systems, for example. The E1-2000 4 acquires data, in part, through one or more external pulse accumulator devices 18 with firmware that gives it independent decision-making ability. The pulse accumulator devices 18 track pulse frequency and aggregate the number of pulses generated by power monitoring circuitry such as a power meter 14 through eight separate electrically isolated channels. In one preferred power monitoring circuit, the frequency of the output pulses is proportional to the instantaneous power tracked by the power monitoring circuit and the aggregate pulse count is proportional to the total watt-hours tracked by the power monitoring circuit 14. In alternative preferred embodiments, the pulse accumulator device 18 is integrated within the E1-2000 4. The push button-switch card 20 partially illustrated in FIG. 2 includes a plurality of manually actuated programmable switches 22. In the preferred embodiment, one programmable switch 22 is programmed to initiate a connection between the E1- 2000 4 and the management device 10 while a second programmable switch 22 is programmed to reset the E1-2000 4. The push-button switch card 20 can also comprise multi-functional switches such as programmable switches 22 that initiate connections between the E1-2000 4 and the management device 10 when actuating a first state and reset the E1-2000 4 when actuating a second state. Another preferred feature of the push button-switch card 20 includes providing a programmable switch 22 that actuates multiple states of the E1-2000 4 according to the time interval the switch is actuated. Preferably, the E1-2000 processor controls the visual and/or the auditory E1- 2000 alarm(s). In the preferred embodiment, when the E1-2000 4 receives a curtailment notification an auditory alarm is actuated for a timed interval that is preferably acknowledged through a push button-switch 22 or deactivated by a lapse of time. As part of the E1-2000 4 installation process, an E1-2000 4 is electrically connected to the end-user's meters 14. Often, end-users utilize one of three types of meters 14. These meters are standard pulse meters, which include time of day kilowatt hour relay meters that can be outfitted with a pulse relay board, pulse meters with internal pulse accumulating circuitry, and smart meters. Standard pulse meters generate output pulses that are proportional to the instantaneous power delivered to a load. A single E1-2000 4 can preferably read up to eight standard pulse meters. Each of the standard meters is connected to the E1-2000 4 through the accumulator device 18 that tracks the frequency of the output pulses and aggregates or counts the meter pulse outputs. The pulse accumulator device 18 comprises a user-defined multiplier circuit that calculates the precise quantity of energy delivered to a load. Because pulse meters with internal pulse accumulating circuitry have RS-232-C ports, these meters are directly connected to the E1-2000 4, bypassing the accumulator device 18. Similarly, smart meters have RS-485 ports that directly connect to the E1 -2000 4. While the E1-2000 4 is capable of interfacing any combination of these meters, its multiple Institute of Electrical and Electronic Engineering ("IEEE") standard interfaces allows the E1-2000 4 to interface many other types of devices or combination of meters and peripheral devices. Moreover, when expansion boards are used, alternative E1-2000 4 embodiments and accumulator devices 18 can interface more than eight standard meters. Preferably, the E1-2000 4 connects to a publicly accessible or a privately accessible distributed network through a modem or a LAN such as an Ethernet device. The Operating System and Application Software are stored in FLASH memory. Preferably, volatile memory such as Random Access Memory ("RAM") stores operating data that is uploaded to the management device 10. However, to compensate for blackouts, brownouts, and power surges, RAM with power supply backup, non-volatile memory such as Electrical Programmable Read-only Memories ("EPROM"), and/or Flash memory is used to store operating data in alternative preferred embodiments to protect and maintain data integrity. Once the E1-2000 4 is properly installed, it initially connects to the management device 10 through a publicly accessible distributed network, such as the Internet 16. All E1 -2000s 4 preferably share a common access provider username and password, which allows each E1 -2000 4 to connect to the distributed network through a common global access account. Upon connectivity, the E1-2000 4 identifies itself and identifies its current Application Software version. If the management device 10, which also supports an on-line Site, determines that the Application Software is outdated, the management device 10 downloads a new version of the Application Software before continuing its initialization routine. The E1-2000 4 uses its remote upgrade capability to seamlessly update Application Software when needed. Preferably, the E1-2000 4 synchronizes its internal clock with the system clock of the management device 10 after it validates its Application Software. Synchronization allows the management device 10 to track load profiles and curtailment events in real-time. The E1-2000 4 then compares the date and time ("timestamp") of its Configuration File with the configuration timestamp stored in management device memory. If the Configuration File attributes differ from the stored attributes, the E1-2000 4 downloads an updated Configuration File that preferably includes the E1-2000 callback frequency, its meter designations, its pulse accumulator device identity, its meter multiplier coefficients, its meter polling frequency, and its Watermark boundaries assigned to each meter the E1- 2000 4 supports. All expired data in memory is then flushed before logging off of the management device 10 and disconnecting from the ISP 12. Once the E1-2000 4 is initialized, preferably the E1-2000 4 connects to the ISP 12 in response to a number of events. The E1-2000 4 connects to the ISP 12 at its scheduled callback intervals, when a Watermark violation occurs, or when initiated by a ring instruction. The scheduled callback intervals establish a standard schedule of connections between the E1 -2000 4 and the management device 10. In this event, the E1-2000 4 automatically connects to the management device 10 at programmed intervals at which time the E1-2000 4 uploads all of its meter and operating data to the management device. A Watermark is a user-defined characteristic, operation, or condition that causes the E1-2000 4 to automatically interface the management device 10 regardless of the E1-2000's 4 callback schedule. Preferably, when a Watermark violation occurs, the E1-2000 4 immediately connects to the management device 10 through the ISP 12. In the preferred embodiment, Watermark violations occur when energy usage is (1) greater than ("HI") a user-defined limit, or (2) less than ("LO") a user-defined limit, or (3) equal to ("EQ") a user-defined limit, or (4) less than a user-defined limit BUT not equal to zero ("LONZ"). Preferably, the E1- 2000 4 compares meter data or peripheral data to its user designated Watermarks each time a meter, accumulator device, or any other device is polled, however, in alternative embodiments the E1-20004 can be programmed to continuously monitor the status of one or more devices and compare the status of these devices with their prescribed Watermarks to detect Watermark violations in real-time. Preferably, all communication between the E1-2000 4 and the management device 10 is initiated by the E1-2000 4. If the E1-2000 modem is called, the E1- 2000 modem will not receive the incoming call. In response to any incoming call, the E1-2000 4 automatically contacts the management device 10 when a communication line is available (the incoming call initiates a "ring instruction"). The E1-2000's 4 call protocol prevents the E1-2000 4 from communicating directly with unauthorized computers or devices and vice versa which protects the E1-2000 4 against external threats and access from unauthorized users such hackers. All communication to the E1-2000 4 is routed through the management device 10 or the LAN. Thus, it is the management device 10 or the LAN that decides whether it is safe to allow a message, a program parameter, a file, or other data to pass to the E1-2000 device 4. Because LAN based E1-2000's 4 exist behind end-user Firewalls, these E1 -2000s 4 are protected by the Firewall security of the end-user's network as well. When the E1-2000 4 connects to an ISP 12 it cycles through a programmed routine. The E1-2000 4 first identifies itself through a unique code, which is a string of characters. The management device 10 compares the code against a stored list of authorized codes. If the code is validated, the management device 10 allows the E1-2000 4 access. The E1-2000 4 then validates its Application Software and synchronizes its internal clock with the system clock of the management device 10. After its clock is synchronized, the E1-2000 4 uploads each of its individual meter or device readings, which are validated by the management device 10 and then stored in a database. If any Watermark violations occurred since the last E1-2000 4 interface, these violations are uploaded, validated, and entered in the database. The E1-2000 4 next downloads its callback connection schedule and then validates its Configuration File. If any curtailment instructions were entered at the on-line Site or sent directly to the management device 10 by the ESP, the E1 -2000 4 downloads curtailment notification instructions before clearing expired or uploaded data, logging off of the management device 10, and disconnecting from the ISP 12. The E1-2000 4 receives a set of instructions from the management device 10 when it is selected by an ESP to curtail energy consumption. These instructions can include defining its callback intervals, actuating a visual and/or audible alarm, and controlling the analog and relay controlled ("digital") voltage channels. Preferably, the management device 10 will instruct the E1-2000 4 to shorten its callback frequency or maintain a continuous connection with the management device 10 which allows end-users and ESPs to receive real-time or near real-time measurements of end-user's energy consumption. During a curtailment period, a visual and/or audible alarm can provide notice to an end-user that an E1-2000 4 is operating under a curtailment notice. If a push-button switch 22 is used to deactivate the alarm, the E1-2000 4 can automatically interface the management device 10 and record the time and frequency the push-button switch 22 was actuated in a database and thus track each time a curtailment notice was acknowledged. Because the analog and relay controlled voltage channels are preferably connected to the end-user's control systems 24, the management device 10 through the E1-2000 4 can directly control user's loads such as air conditioners, lights, pumps, etc., for example, and generators at the ESP's or end-user's direction. The management device 10 can instruct one or multiple analog voltage channels of the E1-2000 4 to produce a range of voltage levels. In the preferred embodiment, two analog voltage channels produce a continuous voltage that range between .95 volts and 2.6 volts. To ensure that the analog voltage channels will interface and control many end-user internal or external control systems, loads, and generators, the E1-2000 4 can be incremented through one hundred different steps within this voltage range. Other low, medium, and high voltage ranges as designated by the IEEE Standards Board (LB 100A - April 23, 1975) are used in alternative preferred embodiments to control low, medium, or high voltage systems. Similarly, the management device 10 can instruct one or more of the relay controlled voltage channels of the E1-2000 4 to generate digital signals of varying pulse widths. In the preferred embodiment, the relay-controlled channels are capable of switching between two voltage states at rates that range between 20 and 90 millisecond intervals. Other pulse width ranges are possible in alternative preferred embodiments. The relays generate digital signals that can interface end-user's controls 24 and allows relatively low power signals to control high- powered devices. Either analog or relay controlled voltage channels can control many combinations of loads, generators, and end-user control systems 24. Their individual or combined use depends on the end-user's facilities and/or the end- user's and ESP's system objectives. Other notable features of the E1 -2000 4 includes (1 ) the ability of the E1 -2000 4 to connect to an access provider such as an ISP 12 through either a LAN or a modem if either device is inoperable; (2) the ability of the E1-2000 4 to connect to an access provider such as a conventional or low-Earth-orbit satellite provider through wireless transceivers; (3) the ability of the E1-2000 4 to access multiple ISP 12 access numbers if one or more of the numbers are in use or are not available; (4) the ability of the E1-2000 4 to access multiple secondary servers supporting the management device 10 if the primary server fails or is inoperable through a LAN or a modem connection; and (5) the E1-2000's 4 use of the LINUX ™ operating system, although other operating systems such as WINDOWS ™, UNIX ™, or operating systems used in SUN ™ workstations or in APPLE™ machines can be used in alternative preferred embodiments. Referring to the drawings, and particularly FIGS. 3 - 5, block diagrams illustrate the structural, sequential, or functional relationships of the Command and Control Center ("CCC") 26 (shown in FIG. 1) that interfaces and supports the management device 10. The CCC 26 comprises end-user records 28, end-user groupings 30, a curtailment decision matrix 32, a curtailment module 34, a curtailment monitor 36, a settlement module 38, notification records 40, load management records 42, and load reduction methods 44. These records and modules reside within a database, memory, or a management system. In the preferred embodiment, the database is a relational database that includes Object Link Embedding ("OLE") that stores information in tables - rows and columns of data and conducts searches by using data in specified rows or columns. The rows of the table represent records (a collection of information about separate items) and the columns represent fields (particular attributes of a record). As shown in FIG. 3, the CCC 26 maintains records describing an end-user's identity 28, notification records 46, load reduction records 48, load-forecast records 50, curtailment istory 52, and E1-2000 4 records 54. The end-user's identity records 28 include the end-user's name and address. The end-users name is simply a field that distinguishes one entity from another. The customer notification records 46 include records of contacts, email, Internet, network, and facsimile addressees. These records are referenced when the management device 10 notifies end-users of market prices, when notifying end-users of curtailment events, or when other trigger action events occur. Preferably, the load reduction records 48 include information on an end-user's displaceable loads, load reduction systems and controls, and generating devices. In the preferred embodiment, a record of load reduction/displacement items includes data that identifies end-user's generators, HVAC units, lighting control units, building control systems used to control other devices, and other items. Preferably, the load reduction records 48 also includes attributes such as (1) the level of kilowatt reduction; (2) the trigger price at which a decision to displace a load, activate a generator, or contact a control system occurs; (3) the number of days, years, and hours within a day a load can be switched off-line, a generator can be activated, or a controller contacted; (4) the notification lead time needed before a curtailment event can occur; and (5) whether the load, generator, or control system is manually or automatically activated or deactivated. Preferably, the load-forecast records 50 provide incremental and aggregate load forecast data over a prescribed period that include data that can be automatically imported into the CCC 26 and is fully compatible with other electronic devices and software such as devices and software that graphically illustrate variables using histograms and plots and/or perform statistical analysis. This feature is useful for anticipating demand peaks and curtailment scheduling. In the preferred embodiment, the load-forecast records 50 include the incremental kilowatt load forecast data over twenty four-hour periods, which are used to calculate end-user baselines for load curtailment performance analysis. The curtailment records 52 preferably include load curtailment information such as the date of the curtailment event, the message(s) sent to the designated end- user contact, the amount of electrical power to be curtailed, the date and time the end-user contact was notified, the start-time and interval of time that the curtailment event will occur, the end-user contact's response to the curtailment notice, load data that allows the end-user or ESP to graph or statistically analyze curtailment performance, and calculated curtailment credits, if applicable. The E1-2000 records 54 preferably include attributes for each E1-2000 4 assigned to end-user facilities. In the preferred embodiment, the E1-2000 records 54 include information that identities whether the E1-2000 4 is in a LAN or in a dial-up mode, the standard communication time interval, the stand-by communication time interval, the meter/pulse channel allocation, the pulse meter or device protocol, the meter multiplier coefficient, the polling time interval, and the Watermark rules, which include an upper and lower data limit validation value. The end-user groupings 30 are records created by the ESP, preferably through the ESP CCC 26. The end-user groupings 30 comprise a collection of records that the ESP forms for load consolidation. The CCC interface allows the ESP to preferably group end-users by group name, available load, zip code or designated areas, notification lead times, or by selected trigger prices 56. The attributes of the ESP selectable groups 58 preferably include the end-users address, the amount of energy committed to curtailment, the notification lead time, the days available for load reduction, the hours available for load reduction, the available load, the trigger prices, and the method of curtailment, whether it be by a manual or an automatic method. The curtailment decision matrix 32 includes Energy Price Exchange data 60 (such as data available from Cinergy or Nymex, for example), generation, Transmission & Distribution ("T&D"), and data that describes the availability of displaceable and curtailable end-user customer loads. The CCC 26 interfaces Energy Price Exchanges to obtain and display indexes of relative prices from selected exchanges or hourly spot market prices or future market prices from selected exchanges. These records provide information that allows end-users to anticipate curtailment events and provide ESPs with lead-times to issue curtailment notices. Preferably, the curtailment decision matrix provides the ESP with end-user- profiling applications. In the preferred embodiment, these applications provide decision support information to the ESP interface 8 that allow ESPs to select end- users based on trigger prices 62, time and day constraints 64, and acquisition and/or cost constraints 66. In the trigger price application 62, the ESP can display and/or issue curtailment notices to end-user groups whose trigger price is less than or equal to hourly spot market prices or to anticipated market prices. Due to generation and T&D constraints, the ESP can display and/or issue curtailment notices to end-user customers based on the their respective curtailable loads and generators for load displacement. This application helps reduce substation and transformer stress caused by excessive time of day demand. The acquisition and cost constraint application 66 reduces the load requirements of an ESP by displaying and/or issuing curtailment notices to end- users based on their committed load reductions and/or their location or the location of a selected feeder line or other selectable components. FIG. 4 illustrates how curtailment events are implemented. The process begins when an ESP is authorized 68. The management device 10 verifies the ESP's user identification and password before allowing access to the CCC 26 and the management device 10. Once the ESP is authorized, it selects the end-user or end-user customer group that will be subject to a curtailment event 70. Group selection may be based on previously defined groups, the energy available for curtailment, notification lead times, trigger price thresholds, the available time for curtailment, or any other criteria or record the ESP elects. After the end-user or group is selected, the ESP sets the curtailment parameters for the selected end- user or group 72. In the preferred embodiment, the ESP can designate the curtailment date, the curtailment start-time, the curtailment end-time, and enter an alphanumeric pager and/or facsimile and/or e-mail message. In alternative embodiments, the ESP can designate other CCC 26 fields. After the curtailment parameters are selected, the ESP can elect a real curtailment 74, a test curtailment 76, or a customer warning notification mode 78. When the ESP elects a real curtailment 74, E1-2000 alarm(s) are activated and pager, facsimile, and e-mail messages ("unified messages") are sent to the end- user'(s) designated contact(s). If the end-user elected automatic control, the E1- 2000 4 initiates load reductions through its relay ("digital") and analog voltage channels. If the end-user elected manual control, the end-user makes load reductions or activates its internal generators after the authorized contact commits to a curtailment. When the ESP elects a test curtailment 76, the ESP has the option of activating the E1-2000 alarm(s) and/or sending the unified messages. Under test curtailment mode 76, any notifications sent to the designated contact(s) will be preceded by a designated message such as "Test Curtailment." When the ESP elects a customer warning notification 78, E1-2000 alarm(s) are activated and unified messages are sent to the designated contact(s). However, like the test curtailment mode 76, no relay or analog voltage channels are activated. In the preferred embodiment, the ESP can put an end-user or group also into a stand-by-mode 80. In a stand-by-mode 80, the management device 10 issues a ring instruction that causes the E1 -2000 4 to connect to the management device 10. After the management device 10 and E1-2000 4 interface, the E1- 2000 4 downloads an updated Configuration File that preferably causes the E1- 2000 4 to call the management device 10 at a greater frequency until the E1- 2000's 4 callback field is reprogrammed. In the preferred embodiment, the curtailment monitor 36 shown in FIG. 4 allows the ESP to display the status of the end-user notification(s) and curtailment performance. Preferably, the status page 82 displays each end-user's name in curtailment by group(s), their load reduction commitments, the potential load reduction capacity, and their notification status. The notification status will indicate if the communication was acknowledged or if a commitment or a rejection was received by the management device 10 shown in FIG. 1. In addition to displaying the status of the end-user's notification, the curtailment monitor 36 allows the ESP to set load trigger points and view load profile and load control information in a variety of user selectable formats including tables and graphs. Load trigger points are set to notify the ESP and end-user when the end-user is not in compliance with a projected or an agreed performance commitment. Curtailment performance 84 can be measured by selecting a performance table or graph that illustrates the end-user's forecasted and actual demand. The difference between these two sets of data is one measure of the end-user's curtailment performance. As shown in FIG. 4, the preferred embodiment also provides a settlement module 38. The settlement module 38 determines end-user credits based on monitored load reduction performance. The end-user curtailment performance interface 86 is a collection of records that provides the ESP with information concerning Energy Price Exchange data, end-user identifications, the time(s) and date(s) of the curtailment event(s), and the actual and projected load reduction(s). End- user settlements can then be calculated in any preferred manner. As illustrated in FIG. 4, credits can be calculated 88 by evaluating load reduction performance and agreed price schedules. FIG. 5 illustrates a block-diagram describing the end-user's curtailment notification and acknowledgement process 40, the end-user's identity and load management attributes 42, and the methods of implementing load management 44. An end-users curtailment notification and acknowledgement 40 begins when an ESP issues a curtailment request. An ESP sends out notification requests to selected end-user contacts individually or collectively by selection of curtailment group(s) 90. Designated end-user contact(s) receive notice through selected messaging or unified messaging or through E1-2000 alarms. When the end- user(s) receive a notice, a designated end-user contact logs onto an on-line Site through the ISP 12 and the customer or end-user interface 6 shown in FIG. 1. In the preferred embodiment, the on-line Site is located on the Internet 16 at Energy1st.com. After designated contact logs onto the Site by providing a valid username and password, the on-line Site immediately prompts the designated contact to acknowledge the curtailment request by either accepting or rejecting the request 92. An acceptance or rejection is then entered into the CCC 26 database, which can be accessed through the customer or end-user interface 6 or the ESP interface 8 by selecting the curtailment history. Preferably, end-user performance can be tracked by selecting any one of a user selectable performance tables or graphs that illustrates the end-user's actual demand 94. Depending on the E1-2000's 4 callback schedule, curtailment can be reviewed on a programmed time delay or in real-time. Preferably, the end-user identity and load management records 42 include notification records 96, load reduction records 98, and historical curtailment records 100. The customer notification records 96 include fields for multiple contact names and addresses for selected or unified messaging. End-user load reduction records 98 include a listing of load reduction/displacement items, such as for example, generators, HVAC units, lighting controls systems, and building control systems that control other devices. These records preferably include attributes that describe projected kilowatt reductions, trigger prices (i.e. dollars/mega-watt hour), number of days, hours per day, and years a particular load or energy generating device can be subject to a curtailment event, notification lead times, the method of curtailment, whether curtailment will occur by a manual or an automatic method, and the method of control whether it be by E1-2000 4 relay or analog control channels. The method of control can further include fields identifying a designated relay for a relay control channel and its designated pulse width(s) and/or the designated analog channel(s), its interval limits, and its defined voltage steps. The historical curtailment records 100 preferably include load curtailment information for current and historical curtailment notices, the dates of messaging including unified messaging, the amount of power committed for curtailment, the day and the time that the designated contact was notified, the designated contact's response, the calculated curtailment credits, and other end-user and ESP selectable data that can be tracked by an end-user or an ESP in a selectable table or graph format. When end-users commit to a curtailment event, the end-user can reduce energy use manually or automatically with the assistance of the E1-2000 4. End-users' load reduction items 102 include any energy-consuming device that consumes power or generating device that provides power. Thus, load reduction occurs when an end-user turns off one or several elevator banks, electric pumps, electric furnaces, electric motors, electric chillers, or even reduces compressor loads on air conditioning units by setting thermostats to higher temperature setting, for example. Load reductions, for example, can also include turning off non- essential lighting or activating light dimmers or ballast controllers or can include activating end-user generators, turbines, or fuel cells. Any load reduction item 102, including the exemplary items described above, is tracked by the CCC 26 and can be part of an end-user curtailment program. Preferably, there are at least two methods of curtailment 104, a manual method and an automatic method. A manual method occurs when dispensable loads are switched off-line or alternative energy supplies are utilized without using the E1- 2000 4. An automatic method occurs through the E1-2000 4 which preferably utilizes standard interfaces such as an RS-232 / RS-485 asynchronous serial communication port or other interfaces and/or its relay and analog voltage channels to switch loads off-line and/or activate alternative energy supplies. An exemplary detailed E1-2000 4 flowchart is illustrated in FIG. 6. The E1-2000 4 flowchart is broken up into four exemplary sections: Section 1 illustrates an E1- 2000 4 overview; Section 2 illustrates a log-in process; Section 3 illustrates a handshake process; and Section 4 illustrates an E1-2000 4 communication process. In Section 1 (106), an E1-2000 4 overview is illustrated. As shown, each end- user facility has one or multiple E1 -2000s 4 that perform protocol conversions for the ISP 12 and the management device 10, data translations and conversions, and message handling. The E1-2000 4 preferably operates on a LINUX™ Operating System that controls the allocation and usage of hardware resources such as memory, processing unit time, and peripheral devices. The E1-2000 4 supports many types of communication protocols including for example Transmission Control Protocol/Internet Protocol ("TCP/IP") that governs the breakup of data streams into packets to be sent via the ISP 12, and the reassembly and verification of the complete messages from packets received by Internet Protocol ("IP"); Point-to-Point Protocol ("PPP") that provides protection for data integrity and security; and Common Object Request Broker Architecture ("CORBA") which works in object-oriented environments where portions of programs (objects) communicate with other objects in other programs, even when the programs are written in different programming languages and/or are operating on different software platforms. A CORBA program makes its request for objects through an Object Request Broker or ("ORB") and thus does not need to know the structure of the program that created the object. In the preferred embodiment, the E1-2000 4 is capable of hosting many objected orientated languages including Delphi and C++ programming languages, for example. In Section 2 (108), the E1-2000 4 login process is illustrated. In Section 2, the E1-2000 4 interfaces the management device 10 through the ISP 12 continuously or at defined time intervals. Each E1-2000 4 connects to the management device 10 through the ISP 12 through either a modem or a LAN. In the preferred embodiment, a LAN sustains continuous connections. In alternative preferred embodiments, either a LAN or a modem sustains continuous or periodic connections. Preferably, each E1-2000 4 possess a unique identification code and share a common user name and password to interface the management device 10 and on-line Site through one global ISP 12 account. However, in alternative preferred embodiments the E1-2000 4 possess unique identification codes, user names, and passwords as a security measure. In Section 3 (110), the E1-2000 4 initial handshake process is illustrated. In Section 3, the E1-2000 4 first interfaces the management device 10 and connects to an on-line Site through the ISP 12. Preferably, the E1-2000 establishes a CORBA communication link before identifying itself and its current Application Software version. The E1-2000 4 then validates its Application Software and synchronizes its internal clock. After synchronizing its clock, the E1-2000 4 preferably executes a number of initial administrative tasks, including: updating its permanent and stand-by communication schedule, assuring its Configuration File, updating its primary and fallback ISP 12 phone numbers and/or its Internet provider addresses, updating its primary and secondary one-line Site addresses, updating its meter configurations, meter identifications, E1-2000 4 meter channel assignments, autopolling intervals, and meter/channel memory maps. In Section 4 (112), a standard E1-2000 4 connection process is illustrated. After the initial handshake process is complete the E1-2000 4 executes its programmed communication process with the management device 10. As previously described, the E1-2000 4 first identifies itself through its unique identification code. The management device 10 compares this code against a stored list of authorized E1-2000 4 codes. When the code is validated, the management device 10 allows the E1-2000 4 access. The E1-2000 4 then validates its Application Software and synchronizes its internal clock with the system clock of the management device 10. After its clock is synchronized, the E1-2000 4 uploads each of its individual meter or device readings, which are validated by the management device 10 and then stored in the CCC 26 database. If any Watermark violations occurred since the last E1-2000 4 interface, these violations are uploaded, validated, and entered in the CCC 26 database. The E1-2000 4 next downloads its callback connection schedule and validates its Configuration File. In the preferred embodiment, when the Configuration File is updated the callback connection field is updated as well. If any curtailment instructions were entered at the on-line Site or sent directly to the management device 10 by the ESP interface 8, the E1-2000 4 downloads curtailment notification instructions before clearing expired or uploaded data, logging off of the management device 10, and disconnecting from the ISP 12. FIG. 7 illustrates a preferred embodiment of the management device 10. The management device 10 is a controller or program that responds to commands from the E1-2000 4, the customer or end-user interface 6, the ESP interface 8, and an administrative interface 122. Preferably, the management device 10 operates in a time-sharing environment of data management, information sharing between ESPs, end-users, Energy Price Exchanges, E1-2000's 4, and other peripheral user interfaces and devices and provides sophisticated network administrative and security features including Firewalls and ring instructions. In the preferred embodiment, the management device 10 comprises a control device 234 that interfaces the network access device through a distributed network and further supports an on-line Site that comprises a communication service 116, an information service 118 such as the CCC 26 database service, and a distributed network service 120. In the preferred embodiment, the distributed network service 120 is a Web Application Service that arranges text, images, and buttons to be read and utilized by Internet users all across the world. As shown in FIG. 7, the management device 10 supports an on-line Site that supports three service elements. Each service element resides on one or more servers that preferably are supported by secondary servers that are connected to a separate access provider such as an ISP 12 then the primary servers they backup and support. The secondary servers mirror the primary servers in their services and functionality. The communication service 116 is preferably a server-side device that allows the E1 -2000s 4 to seamlessly interface a control device 284 shown in FIG. 1. The control device 284 is a circuit, software or any other device, system, or code that connects hardware or platforms so that information can be moved from place to place. Preferably, the communication service 116 supports TCP/IP, PPP, and CORBA communication protocols. The communication service 116 supports many other communication protocols in alternative preferred embodiments including Serial Line Internet Protocol ("SLIP") communication protocol, for example. Moreover, the communication service 116 can provide a secure connection between devices meaning the information end-user, E1 -2000 and ESP interfaces 6, 4, and 8 provide, such as energy curtailment goals and realtime demand, can be encrypted so that it cannot be read or intercepted by unauthorized devices or users. Preferably, the database service 118 is also a server-side αevice. in tne preferred embodiment, the database service 118 comprises a server that supports a relational database that has OLE capabilities that stores information in tables - rows and columns of data. The rows of the table represent records and the columns represent fields. The database allows searches to be conducted in which the database matches information from a field in one table with information in a corresponding field of another table to produce a third table that combines requested data from both tables in a high-resolution graphic or table format. In other words, the preferred database uses values from multiple fields to relate information to other fields. Preferably, the Web Application service 120 hosts all end-user and ESP related interfaces 6 and 8 and functions that are accessible through the customer or end- user interface 6, the ESP interface 8, and the administrative interface 122. It further comprises a group of related text files that contain not only Hypertext Markup Language ("HTML") and Extensible Markup Language ("XML") tags as in standard Internet documents, but also can contain commands, written in scripting language such as Visual Basic Script ("VBScript") that can be executed by the servers. The Web Application service 120 enables end-users and ESP's to customize the viewing, delivery, and exchange of information through standard Uniform Resource Locators ("URL") through Web browsers, such as Microsoft Internet Explorer™ or Netscape Navigator™, for example. FIGS. 8 - 24 illustrate the Graphical User Interfaces ("GUI") that represent programs, files, and end-user and ESP options by means of icons, menus, and dialog boxes. The user can activate these options by pointing and clicking a mouse, entering a keyboard command, or using many other communication devices. All of the icons, menus, and dialog boxes function the same way across many software platforms, because the GUI provides standard software routines that make these functions compatible with many URLs. Other network connections are provided in alternative preferred embodiments including command-line-interfaces and menu-driven interfaces. A command-line-interface is an interface that allows users to enter commands. A command-line-interface can be considered more difficult to use than GUIs because they are programmable interfaces. Menu-driven interfaces can also be considered easier to use than command-line-interfaces as these interfaces provide menus of all available user choices and options. FIG. 8 illustrates an exemplary start-page of the on-line Site. This page is accessible through the Internet 16 and serves to welcome users, provide information about the Site, and direct the users to energy information, rate analysis, management of loads and energy supplies, and set up modifications after the end-user or ESP logs on to the on-line Site using their usernames and passwords. In other words, this page functions as a table of contents of the Site. A brief overview of the ESP accessible pages is described below. After an ESP selects Energy Info, the on-line Site directs the user to FIG. 9. FIG. 9 illustrates an exemplary address dialog-box. As shown, Accounts 124 is a menu-driven field that allows ESPs to view existing accounts or add new accounts to the Site. This page preferably records address and telephone data. FIG. 10 illustrates an exemplary contact dialog-box that solicits the designated contact's addresses. These fields preferably include primary and secondary pager access numbers 126 and 128, a facsimile number 132, and e-mail or net address(es) 130. FIG. 11 illustrates an exemplary load summary dialog-box. The exemplary load- summary dialog-box preferably displays a summary of reduction/displacement items 148 that can be updated by a click of a mouse. The exemplary load-dialog- box preferably includes reduction/displacement item attributes that indicate if the items are active 134, the kilowatt reduction 136, the trigger method whether it be manual or method 138, the notification lead times 140, the days each item is available in the season 142, the hours per day 144, and the trigger price 146. FIG. 12 illustrates an exemplary option dialog-box. The exemplary option dialog- box allows the ESP to identify the E1-2000 4 and its associated peripheral load(s) or generator(s) that are referred to as items 150. It further includes attributes on each item that preferably includes kilowatt reductions 152, a trigger price 154, the days per year 156, hours per day 158, notification lead time in minutes 160, and whether the item is activated and/or deactivated by the analog and/or relay 5 controlled ("digital") voltage channels 162 - 168. FIG. 13 illustrates an exemplary end-user forecast. The end-user forecast is selectable by customer and date and preferably provides an hourly forecast of expected energy use in kilowatts. 10. FIG. 14 illustrates an exemplary communication summary. The communication summary preferably summarizes the curtailment date 170, whether a unified message or selected message was sent 172, the amount of energy committed for curtailment 174, the date and time the end-user contact was notified 176, the 15 expected curtailment time 178, and the end-user's contact response to the curtailment notification 180. FIG. 15 illustrates an exemplary E1-2000 4 dialog-box describing a HVAC interface assigned to an exemplary zone. FIG. 15 shows all of the definable 20 fields of an interface, which includes the device assignment or owner 182, the type of device or name 184, the zone identification 186, the communication line access field and telephone number 190 and 192, the password 194, the MAC address 196, the communication minutes of the device 198, the temporary communication minutes 200, a description of the device 204 and a list of user 25 selectable options 206. FIG. 15 further illustrates exemplary meter attributes. It illustrates the zone identifications of multiple standard meters 208, their respective accumulator channel assignments 218, their alias 210, the type of meter 212, their autopolling 30 intervals 216, and their multipliers. Because the aggregate pulse count of the exemplary standard meter of FIG. 15 is proportional to the total watt-hours tracked by the meter, a multiplier field is provided which allows the management device 10 to calculate the precise amount of energy monitored by the meter. As illustrated, the total watt-hours tracked by the exemplary standard meter of FIG. 15, is directly proportional to the aggregate pulse count of the standard meter and thus the multiplier is one. In alternative preferred embodiments, the multiplier can be any real number that when multiplied by the aggregate pulse count calculates the total watt-hours consumed by the device. FIG. 16 illustrates an exemplary log of an exemplary zone. Besides identifying the date 220 and time 224 of the communication between the E1-2000 4 and management device 10 it also provides a status message 226 indicating the condition of the communication link. FIG. 17 illustrates an exemplary E1-2000 dialog box assigned to another exemplary zone. It identifies the alias 210, the type of device 212, the multiplier 214, the autopolling interval 216 in minutes, and a list of user selectable options 206. FIG. 18 illustrates an exemplary Watermark dialog-box of the exemplary zone. In the preferred embodiment, the Watermark dialog-box includes the type 228, which identifies HI, LO, EQ, and LONZ fields, the limits for these respective fields 230, and whether the Watermark zone is active 232 or suspect 234. A summary of recent Watermark violations is also illustrated which identifies the rule 236 that was violated, the timestamp 238, the kilowatt reading that caused the violation 240, and whether the management device 10 was notified 242 of the violation. FIG. 19 illustrates an exemplary application function. As shown, the ESP can sort by end-user names 244 or by ESP definable groups 246. Each end-user selected by name or by groups can be displayed with the number of kilowatts they committed to curtailment 248, their respective notification lead times 250, the days the commitments are available 252, the hours per day 254, the total kilowatts available 256, the trigger price 258, and the communication or dispatch method 260, whether it be by alarm or messaging. FIG. 20 illustrates an exemplary start-page dialog-box of the curtailment system. An ESP must provide a valid usemame and password before being granted access. FIG. 21 illustrates an exemplary application function for the curtailment system. As shown, the ESP can sort by end-user names or ESP definable groups. ESP selectable fields can further define each end-user. These fields preferably include energy use 264, available power for curtailment 266, minimum or maximum lead times 268, and curtailment duration intervals 270. FIG. 22 illustrates the exemplary message initiation functions. As shown, the ESP can customize its unified messaging and schedule their dispatch. FIG. 23 illustrates an exemplary curtailment notification/acknowledgement status summary. The summary includes end-user addresses 272, designated contacts 274, curtailment notification status 276, the time of acknowledgement 278, their kilowatts committed 280, and the end-user's potential kilowatt reductions 282. FIG. 24 illustrates an exemplary user-defined graphic. As shown, incremental kilowatt load forecast data over twenty four-hour periods is graphed against actual demand. The difference between these graphs is one measure of the end- user's curtailment performance. From the foregoing description is should be apparent that the system and method of the present invention facilitates energy redistribution and trade initiated by ESPs in response to energy market conditions and time and day constraints. The invention provides monitoring, control, and analysis of load profiles and energy market prices that cover a large number of distributed end-users. One preferred embodiment of the invention relies on the infrastructure of the Internet utilizing a star topology and TCP/IP and CORBA protocols. The CORBA protocol streamlines the communication between end-users, ESPs and E1 -2000s 4 with the management device 10 and on-line Site thus enabling a large number of users to report to one management device 10 or a single server. Moreover, one preferred embodiment monitors multiple power consuming devices at decentralized locations to initiate load-shedding processes and also utilizes end- users generation capacity for load displacement, initiating manual and automatic load reduction plans using unified messaging, and can make unutilized energy available for resale on the spot or open market through its interface(s) to Energy Price Exchanges. The foregoing description has described only a few of the many forms that the invention can take, and should therefore be taken as illustrative rather than limiting. It is only the following claims, including all equivalents, which are intended to define the scope of the invention. IMAGE EVALUATION TEST TARGET QA-3 .25 1.4 1.6 150mm 6" USA FILE: 485.C This File handles the ppp connection to the isp. It is executed when kw_client is scheduled to communicate its readings to the database. =*/ #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <signal.h> //#defιne DETACH l* baudrate settings are defined in <asm/termbits.h>, which is included by <termios.h> * / #define BAUDRATE B9600 /* change this definition for the correct port * / //#defιne MODEMDEVICE dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX compliant source * / #defιne FALSE 0 #define TRUE 1 volatile int STOP=FALSE; void onkill(int which) { if (which==SIGTERM || which==SIGHUP) { printf("Process stopped by interruptλn"); STOP=TRUE; } } main(int argc, char **argv) //argv[1]==modemname { int fd,c, res, res2, child; struct termios oldtio.newtio; char buf[255]; char devicename[64]; char devicelock[64]; struct stat st; int superparent; #ifdef DETACH fclose(stdin); fclose(stdout); superparent=fork(); if (superparent > 0) { //waitpid(superparent,NULL,0); exit(O); } freopen(7tmp/callonring","a",stdout); freopen("/tmp/callonring","r",stdin); freopen("/tmp/callonring" ) "a" 1 stderr); #endif signal(SIGTERM,onkill); signal(SIGHUP,onkill); /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. */ // sleep(15); //to wait for a connecting PPPD memset(devicename,0,64); if (argc<2) { strcpy(devicename,7dev/ttyS1 "); printf("No devicename specified, using %s\n",devicename); } else strncpy(devicename,argv[1],63); sprintf(devicelock,"/var/lock/LCK..%s",strrchr(devicename I '/ , )+1); fd=-1; while (fd < 0) { fd = open(devicename, O_ RDWR | O_NOCTTY | O_NONBLOCK); if (fd<0) perror("Error opening modem: "); sleep(5); } printf("Modem device %s opened!\n",devicename); tcgetattr(fd,&oldtio); /* save current serial port settings * / bzero(&newtio, sizeof(newtio)); / * clear struct for new port settings * / /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity, 1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters 7 //newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_cflag = BAUDRATE | CLOCAL | CS8 | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) newtio.cjflag = IGNPAR | ICRNL; /* Raw output. 7 newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program 7 newtio.cjflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here 7 newtio.c_cc[VlNTR] = 0; /* Ctrl-c 7 newtio.c_ccr QUIT] = 0; /* Ctrl-\ 7 newtio.c_cc[VERASE] = 0; /* del 7 newtio.c_cc[VKILL] = 0; / * @ 7 newtio.c_cc[VEOF] = 4; /* Ctrl-d 7 newtio.c_cc[VTIIvlE] = 0; /* inter-character timer unused 7 newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives 7 newtio.c_cc[VSWTC] = 0; / * ΛO' 7 newtio.c_cc[VSTART] = 0; / * Ctrl-q 7 newtio.c_cc[VSTOP] = 0; I * Ctrl-s 7 newtio.c_cc[VSUSP] = 0; / * Ctrl-z 7 newtio.c_cc[VEOL] = 0; / * '\0' 7 newtio.c_cc[VREPRINη = 0; / * Ctrl-r 7 newtio.c_cc[VDISCARD] = 0; / * Ctrl-u 7 newtio.c_cc[VWERASE] = 0; / * Ctrl-w 7 newtio.c_cc[VLNEXη = 0; /* Ctrl-v 7 newtio.c_cc VEOL2] = 0; / * '\0' 7 /* now clean the modem line and activate the settings for the port 7 tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); /* terminal settings done, now handle input In this example, inputting a 'z' at the beginning of a line will exit the program. 7 write(fd, ,, ?\r\r\nRD\n",7); while (STOP==FALSE) { /* loop until we have a terminating condition 7 /* read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars, res will be set to the actual number of characters actually read 7 // printf("starting read/write cycle.. Λn"); //res = read(fd,buf,255); //this line worked if BLOCKING fflush(NULL); res=0; memset(buf,0,255); while (STOP==FALSE && !strchr(buf,10)) { res2=read(fd,buf+res,255-res); if (res2>0) { printf("%s",buf); res+=res2; } else { //sleep(1); memset(buf,0,255); gets(buf); write(fd,buf,strlen(buf)); sleep(1); } } if (STOP==TRUE) { printf(Εxiting...\n"); break; } //check for a lock file! (ie from pppd) //printf("Checking for lock: %s \n",devicelock); if (stat(devicelock,&st)==0) { printf("Sleeping because of modemlock: %s\n",devicelock); while (STOP==FALSE && stat(devicelock,&st)==0) sleep(10); printf("Lock released !\n"); tcflush(fd, TCIOFLUSH); } //else //printf("No device lock found\n"); buf[res]=0; /* set end of string, so we can printf 7 printf("%s", buf); fflush(NULL); if (strstr(buf,"RING") || strstr(buf,"Ring")) { child=fork(); if (child==0) { sleep(20); execl('7bin/sh ,, ,7bin/sh","/usr/sbin/ppp-on",NULL); } else { printf("Spawning child!\n"); fflush(NULL); while(STOP==FALSE && !waitpid(child,NULL,WNOHANG)) sleep(10); printf("Done waiting for child!\n"); c!ose(fd); sleep(1); fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd<0) perror("Error opening modem: "); fflush(NULL); } } //if (buf[0]=='z') STOP=TRUE; } /* restore the old port settings 7 tcsetattr(fd,TCSANOW,&oldtio); } FILE: callonring.c This file handles negotiation with the isp after a modem connection has been made. */ #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <signal.h> #defιne DETACH #defιne PPPTIMEOUTMINUTES 15 /* callonring listens to the specifies serial port [/dev/ttyS1 by default] unless the -o option is specified (don't listen to any port). When a RING comes in from the modem, or a SIGALRM is received, callonring launches /usr/sbin/ppp-on. If the modem was launched by SIGALRM, and it receives a SIGHUP, callonring will kill (SIGTERM) the pppd process. If callonring is listening to its serial port, and a lock file is created (/var/lock/{portname}), callonring will suspend listening to the port, and will ignore SIGALRM, as long as the lock file exists. callonring waits 20 seconds after receiving a RING or SIGALRM before dialing. This is to allow the incoming RING phone-call to fully terminate before attempting to dial. 7 /* baudrate settings are defined in <asm/termbits.h>, which is included by <termios.h> 7 #defιne BAUDRATE B38400 /* change this definition for the correct port 7 //#define MODEMDEVICE 7dev/ttyS1" #define _POSIX_SOURCE 1 /* POSIX compliant source 7 #defιne FALSE 0 #define TRUE 1 typedef struct { int ready; char password[256]; char username[256j; char phone[256]; } ispstruct; //global int signal_alarm; int sighup; int ispcount; ispstruct isps[15]; volatile int STOP=FALSE; LoadlSPsO { FILE * f1; char buf[1024]; char *p1; f1=fopen(7etc/pepper/isps","r"); if (!f1) . { printf("Error opening /etc/pepper/isps!\n"); return(-1); } ispcount=0; while (!feof(f1)) { memset(buf,0,1024); fgets(buf,1023,f1); printf("\n\nLine->|%s|\n",buf); p1=buf; while (isspace(Tpl)) p1++; if ( * p1== , #' || strlen(p1) < 11) continue; p1=strtok(p1 ,":"); strcpy(isps[ispcount].username,p1); p1=strtok(NULL,":"); strcpy(isps[ispcount]. password, p1); p1=strtok(NULL,":\n"); strcpy(isps[ispcount].phone,p1); isps[ispcount].ready=1 ; printf(":%s:%s:%s:\n\n",isps[ispcount].username,isps[ispcount].password;isps[isp count], phone); ispcount++; } fclose(fl); return(O); } void Log(char *message, char *mess2) { time_t now; struct tm *st; char buf[256]; now=time(NULL); st=(struct tm *)localtime((time_t *)&now); memset(buf,0,256); sprintf(buf,"[%24.24s] %s\n",asctime(st),message); if (mess2) printf(buf,mess2); else printf uf); fflush(NULL); return; } int fexist(char * fιlename) { FILE * fl; if (!(f1=fopen(filename,V))) return(O); else { fclose(fl); return(1); } } void onkill(int which) { if (which==SIGTERM) { LogC'Process stopped by interrupt (SIGTERM)",NULL); STOP=TRUE; } } void onalarm(int which) { if (which==SIGALRM) { Log("Got SIGALRM, start dialing.",NULL); signal_alarm=1; //now re-install the signal handler signal(SIGALRM,onalarm); } if (which==SIGHUP) { Log("Got SIGHUP, kill pppd.",NULL); signal_alarm=0; sighup=1; signal(SIGHUP,onalarm); } } int writepidfiIe(const char *filename) { FILE *f1; f 1 =fopen(filename,"w"); if (!f1) return(-1); fprintf(f1,"%d\n",getpid0); fclose(f1); retum(O); } int PrepPPPEnvironment(int whichtry) { char buf[1024]; if (isps[whichtry].ready==0) return(-1); memset(buf,0,1024); sprintf(buf,"PASSWORD=%s",isps[whichtry].password); putenv(buf); memset(buf,0,1024); sprintf(buf,"ACCOUNT=%s",isps[whichtry].usemame); putenv(buf); memset(buf,0,1024); sprintf(buf,"TELEPHONE=%s",isps[whichtry].phone); putenv(buf); return(O); } int LaunchConnection(int whichtry) //no longer used!!!!!!! { char buf[1024]; int success; pid_t child; success=0; if (isps[whichtry].ready==0) return(O); memset(buf,0,1024); sprintf(buf,"PASSWORD=%s",isps[whichtry].password); putenv(buf); memset(buf,0,1024); sprintf(buf,"ACCOUNT=%s",isps[whichtry].username); putenv(buf); memset(buf,0,1024); sprintf(buf,"TELEPHONE=%s",isps[whichtry].phone); putenv(buf); printf("LaunchConnection() launched with %s\n", buf); fflush(NULL); child=fork(); if (child==0) { execl("/bin/sh",7bin/sh",7usr/sbin/ppp-on",NULL); } else { putenv("PASSWORD=null"); while(!waitpid(child,NULL,WNOHANG)) { if (fexist(7var/lock/corbanet")) { success=1; sleep(5); } else { sleep(1); } } } return(success); } main(int argc, char **argv) //argv[1]==modemname { int fd,i, c, res, res2, child; struct termios oldtio.newtio; char buf[255]; char devicename[64]; char devicelock[64]; struct stat st; int superparent; int nonlistener; int alarm_up; time_t now, timestop; int success,tries; alarm_up=0; signal_alarm=0; nonlistener=0; sighup=0; #ifdef DETACH fclose(stdin); fclose(stdout); superparent=fork(); if (superparent > 0) { //waitpid(superparent,NULL,0); exit(O); } writepidfιle("/var/lock/callonring.pid"); freopen(7var/log/callonring","a",stdout); freopen(7var/log/callonring","r",stdin); freopen(7var/log/callonring","a",stderr); #endif signal(SIGTERM,onkill); //signal(SIGHUP,onkill); signal(SIGALRM,onalarm); signal(SIGHUP,onalarm); for (i=1;i<argc;i++) { if (strcmp(argv[i],"-o")==0) { nonlistener=1; LogC'This callonring is a non-listener.",NULL); } } if (LoadlSPsO) { //LoadDefaultlSP(); } for(i=0;i<ispcount;i++) { printf("Loaded %d: %s\n",i,isps[i].phone); } if (inonlistener) { /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. 7 // sleep(15); //to wait for a connecting PPPD memset(devicename,0,64); if (argc<2) { strcpy(devicename,7dev/ttyS1 "); Log("No devicename specified, using %s",devicename); } else strncpy(devicename,argv[1],63); sprintf(devicelock,"/var/lock/LCK..%s",strrchr(devicename,'/')+1); fd=-1; while (fd < 0) { fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd<0) perror("Error opening modem: "); sleep(5); } LogC'Modem device %s opened !",devicename); tcgetattr(fd,&oldtio); / * save current serial port settings 7 bzero(&newtio, sizeof(newtio)); I* clear struct for new port settings 7 /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity, 1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters 7 //newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CREAD; I * IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) 7 newtio.cjflag = IGNPAR | ICRNL; /* Raw output. 7 newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program 7 newtio.cjflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here 7 newtio.c_cc[VINTR] = 0; /* Ctrl-c 7 newtio.c_cc[VQUITj = 0; /* Ctrl-\ 7 newtio.c_cc[VERASE] = 0; /* del 7 newtio.c_cc[VKILL] = 0; /* @ 7 newtio.c__cc[VEOF] = 4; /* Ctrl-d 7 newtio.c_cc[VTIME] = 0; /* inter-character timer unused 7 newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives 7 newtio.c xr SWTC] = 0; /* '\0' 7 newtio.c_cc[VSTART] = 0; /* Ctrl-q 7 newtio.c_cc[VSTOP] = 0; /* Ctrl-s 7 newtio.c_cc[VSUSP] = 0; /* Ctrl-z 7 newtio.c_cc[VEOL] = 0; /* '\0' 7 newtio.c_cc[VREPRINT] = 0; /* Ctrl-r 7 newtio.c_cc[VDISCARD] = 0; /* Ctrl-u 7 newtio.c__cc[VWERASE] = 0; /* Ctrl-w 7 newtio.c_cc[VLNEXη = 0; /* Ctrl-v 7 newtio.c_cc[VEOL2] = 0; /* '\0' 7 /* now clean the modem line and activate the settings for the port 7 tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); /* terminal settings done, now handle input In this example, inputting a 'z' at the beginning of a line will exit the program. 7 }//endif non-listener write(fd,"+++ATZS7=45S0=0Q0V1&c1 E1\n",25); while (STOP==FALSE) { / * loop until we have a terminating condition 7 / * read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars, res will be set to the actual number of characters actually read 7 //res = read(fd,buf,255); //this line worked if BLOCKING fflush(NULL); memset(buf, 0,255); if (inonlistener) { res=0; memset(buf,0,255); while (STOP==FALSE && !strchr(buf,10) && !signal_alarm) { res2=read(fd,buf+res,255-res); if (res2>0) res+=res2; sleep(1); } if (STOP==TRUE) { Log("Exiting...",NULL); break; } }//endif non-listener else sleep(1); //check for a lock file! (ie from pppd) // printf("Checking for lock: %s \n",devicelock); if (stat(devicelock,&st)==0) { Log("Sleeping because of modemlock: %s",devicelock); while (STOP==FALSE && stat(devicelock,&st)==0) sleep(10); LogC'Lock released!",NULL); if (Inonlistener) tcflush(fd, TCIOFLUSH); } // else // Log("No device lock found",NULL); if (Inonlistener) { buf[res]=0; /* set end of string, so we can printf 7 Log("READ FROM MODEM: %s", buf); } if (strstr(buf,"RING") || strstr(buf,"Ring") || signal_alarm) { if (signal_alarm) alarm_up=1; //it was SIGALRM, not RING that brought up link! else alarm_up=0; success=0; tries=0; while (Isuccess && tries < ispcount) { child=fork(); if (child==0) { if (!PrepPPPEnvironment(tries)) execl("/bin/sh","/bin/sh","/usr/sbin/ppp-on",NULL); else exit(0); //success=LaunchConnection(tries); } else { Log("Spawning child!",NULL); now=time(NULL); timestop=now+(60*PPPTIMEOUTMINUTES); while(STOP==FALSE && !waitpid(child,NULL,WNOHANG) && now < timestop) { if (fexist("/var/lock corbanet")) { success=1; Log("Success",NULL); } now=time(NULL); if (now >= timestop) Log("PPPTIMEOUT reached, killing connection.",NULL); if (sighup) Log("Killing PPPD because of SIGHUP.",NULL); if (alarm_up && !signal_alarm) LogC'Killing PPPD because alarm has been rescinded.",NULL); if ((alarm jp && !signal_alarm) || sighup || now >=timestop) { kill(child.SIGTERM); sighup=0; } sleep(5); } LogC'Done waiting for child!",NULL); unlink("/var/lock/corbanet"); } tries++; } signal_alarm=0; if (inonlistener) { close(fd); sleep(1); fd = open(devicename, O_RDWR | OjMOCTTY | OjMONBLOCK); if (fd<0) perror("Error opening modem: "); } fflush(NULL); } //if (buf[0]=='z') STOP=TRUE; } / * restore the old port settings 7 if (Inonlistener) tcsetattr(fd .TCSANOW, &oldtio) ; } FILE: client.cxx This file handles the client side of the corba talk ============================================================*/ #include "iccm_client.h" #include "storage, h" #include "omnithread.h" #include "kwjnserter.hh" #include "spa2.h" #include "logcodes.h" #include "notif.h" #include <sys/socket.h> #include <net/if.h> #include <sys/ioctl.h> #include <netinet/in.h> #defιne USETHREADS #ifdef USETHREADS #include <pthread.h> //need some extra globals if using threads: char *thread_mac_addr; storageobj * thread_storage; schedulerobj *thread_corbaschedule; watermarksobj *thread_watermarks; spa2 *spaboard; #endif static CORBA: :Object_ptr getObjectReference(CORBA::ORB_ptr orb); //global variables int commandargcount; char **commandargs; int signalpoll; char argvlog[256]; int suppressupgrades; int timed_dial ime; int timed_dial_happened; int firstcommo; CollectionBase sendlogitems; notifications notifs; int killfpid(int which, const char * 1ϊlename) { FILE I; char bufT256]; if (!(f1=fopen(fιlename,"r"))) { //Log(PIDERR,"Unable to find pid for foreign program!"); //this was happening way too often (impossible to read logs! return(-1); } fgets(buf,255,f1); fclose(fl); if (atoi(buf)>0) kill(atoi(buf),which); return(O); } int fexist(char *filename) { FILE *f1; if (!(f1=fopen(filename,"r"))) return(O); else { fclose(fl); return(1); } } void WriteMinutesToFile(const char *filename,long numminutes) { FILE I; f 1 =fopen(filename,"w"); if (!f1) { printfC'Unable to create swatchdog target file: %s\n",filename); return; } fprintf(f 1 ,"%ld\n",numminutes); fclose(fl); return; } void onhup(int which) { signalpoll=1; signal(SIGHUP,onhup); } int corbatalk(char *mac_addr, storageobj *storage, schedulerobj * corbaschedule, watermarksobj *watermarks) { CORBA: :ORB_ptr orb; CORBA::BOA_ptr _myboa; int ij.ret; kwjnserter_var myobjRef; kwjnserter *kwi, *prekwi; dateobj temptime; char buf[256]; time in gmt; long iccmid; long meterid; char *p1; const char *p2; int needupgrade; watermarkviolation *tempwm; long tempver; timej temptimet; long notificationcount; notificationobj *tempnotif; long newaddminutes; ORBsobj orbs; int orbnum; int connected; ORB *temporb; FILE *f1; orbs.Load(7etc/pepper/orbs"); CORBA: :Object_var obj; Log(INFO,"Entering CORBATALK()"); orbnum=0; connected=0; #ifdef CORBAFALLBACK while ({connected && orbnum<orbs.cb.Count()) { temporb=(ORB *)orbs.cb.ltem(orbnum); if (itemporb) { Log(CORBAERR,"Error locating orbs in memory"); return(-1); } if ((f1=fopen(7etc/omniORB.cfg","w"))==NULL) { orbnum++; printf("Error opening /etc/omniORB.cfg for writing. \n"); continue; } fprintf(f1 ,'ORBInitialHost %s\nORBInitialPort %s\n",temporb->host,temporb- >port); fclose(fl); orbnum++; printf("Trying ORB: '%s' '%s' \n",temporb->host,temporb->port); orb=NULL; try{ orb=CORBA::ORBJnit(commandargcount, commandargs,"omniORB2"); } catch(...) { Log(CORBAERR,"Error creating CORBA ORB."); continue; } try { _myboa=orb->BOAJnit(commandargcount, commandargs,"omniORB2j3OA"); } catch(...) { Log(CORBAERR,"Error creating BOA."); continue; } try { obj=getObjectReference(orb); } catch(...) { Log(CORBAERR,"Error connecting to to CORBA object."); continue; } if (CORBA: :is_nil(obj)) { Log(CORBAERR,"obj says that it is _nil()."); continue; } if ((unsigned long)orbnum >= orbs.cb.Count()) { Log(CORBAERR,"Unable to connect to ANY CORBA object!"); return(1); } connected=1; } #else orb=NULL; Log(CORBAERR,"About to run ::ORBJnit()"); try { orb=CORBA::ORBJnit(commandargcount, commandargs, "omniORB2"); } catch(...) { Log(CORBAERR,"Error creating CORBA ORB."); return(-1); } Log(CORBAERR,"About to run ::BOAJnit0"); try { _myboa=orb->BOAJnit(commandargcount, commandargs,"omniORB2_BOA"); } catch(...) { Log(CORBAERR,"Error creating BOA."); return(-2); } if (orb==NULL) { Log(CORBAERR,"The orb is NULL, aborting corbatalk()"); return(-1); ' } if (_ yboa==NULL) { Log(CORBAERR,"The _myboa is NULL, aborting corbatalkQ"); return(-1); ■ } Log(CORBAERR,"About to GetObjectReference()"); try { obj=getObjectReference(orb); } catch(...) { Log(CORBAERR,"Error connecting to to CORBA object."); return(-3); } Log(CORBAERR,"About to see if obj is_nil()"); if (CORBA::is_nil(obj)) { Log(CORBAERR,"obj says that it is _nil()."); return(-4); } #endif utime("/tmp/commosuccess",NULL); //touch the times to now Log(CORBAERR,"About to ::_narrow(obj)"); try { prekwi=kwJnserter::_narrow(obj); } catch(...) { Log(CORBAERR,"unable to _narrow() prekwi."); return(1); } if (Iprekwi || CORBA: :is_nil(prekwi)) { Log(CORBAERR,"After _narrow, prekwi says that it is _nil()"); return(-3); } char Tiewobj; printf("Old Object IOR: %s\n",orb->objectJo_string(prekwi)); try { prekwi->KWFactory(newobj); } catch(...) { Log(CORBAERR,"Factory failed!"); return(-1); } printfC'New Obj IOR: %s\n",newobj); try { obj=orb->stringJo_object(newobj); } catch(...) { Log(CORBAERR,"Error in stringJo_object"); } try { kwi=kw_inserter::_narrow(obj); } catch(...) { Log(CORBAERR,"Unable to narrow obj to kwi"); } if (!kwi || CORBA::is_nil(kwi)) { Log(CORBAERR,"After_narrow, kwi says that it is _nil()"); return(-3); } try { kwi->Log(0L,LOG 3OTFACTORY,"New Factory Object!",LOGTIMEjNOW,LOGJNFO3); } catch(...) { Log(CORBAERR,"Unable to insert into the server log."); return(-1); } try { iccmid=kwi->HWLogin(mac_addr); } catch (...) { Log(CORBAERR,"Error using the kwjnserter object!"); retum(-4); } Log(CORBAERR,"Performed HWLOGIN"); //we are now using a file (/tmp/commosuccess) instead of a signal //killfpid(SIGCONT,"/var/lock/swatchdog.pid"); #ifdef USETHREADS /* if (spaboard->buttons || spaboard->chirps) { sprintf(buf,"Buttons: %d Chirps: %d",spaboard->buttons, spaboard->chirps); try { kwi->Log(iccmid,LOGj3UTTONS,buf,LOGTIME_NOW,LOG_ACK3); } catch(...) { Log(CORBAERR,"Unable to insert into the server log."); return(-1); } } 7 #endif if (firstcommo) { p1=new char[12]; memset(p1 ,0,12); sprintf(p1, "First Pass"); sendlogitems.Add((void *)p1); firstcommo=0; } if (sendlogitems.CountO > 0) { Log(INFO,"Trying to send misc log items to the server."); for (i=0;i< (int)sendlogitems.Count();i++) { if ((p2=(const char *)sendlogitems.Item(i))) { try { kwi->Log(iccmid,LOG_MISC,p2,LOGTIME_NOW,LOGJJNK); } catch(...) { Log(CORBAERR,"Unable to insert into the server log."); } sendlogitems.Remove(i); } } } else { Log(INFO,"No misc log items to send to the server."); } Log(INFO,"Done sending misc log items to the server."); /* if (firstcommo) { try { kwi->Log(iccmid,LOG_FlRSTPASS,"First Pass",LOGTIME_NOW,LOGJNFO9); } catch(...) { Log(CORBAERR,"Unable to insert into the server log."); } firstcommo=0; } 7 try{ tempver=kwi->Version(iccmid,VERSION_CODIFIED,VERSlON_HUMAN); } catch(...) { Log(CORBAERR,"Error checking client version"); return(-5); } if (tempver > VERSION_CODIFIED) { needupgrade=1; Log(INFO,"We need to upgrade kw_client (after uploading readings)."); try { kwi->Log(iccmid,LOG_NEEDUPGRADE,"This ICCM needs to perform remote upgrade.",LOGTIME_NOW,LOGJNFO9); } catch(...) { Log(CORBAERR,"Unable to insert log entry on server."); } } else needupgrade=0; if (needupgrade && suppressupgrades) { sprintf(buf,"Upgrades are suppressed for %d more communications.",suppressupgrades); Log(INFO,buf); suppressupgrades-; needupgrade=0; // <-- the actual suppression, tada } if (argvlog[0]) { Log(INFO.argvlog); try{ kwi- >Log(iccmid,LOG_COMMANDLINE,argvlog,LOGTIME_NOW,LOG_UNK); } catch(...) { Log(CORBAERR,"Unable to insert log entry on server."); } } in_gmt=0L; try { in_gmt=kwi->GetGMT(); } catch(...) { Log(CORBAERR,"Unable to fetch time from server."); return(-6); } if (stime(&in_gmt)) sprintf(buf,"Error setting local clock; perhaps kw_client was started by a non- root user."); else sprintf(buf,"Just set the time to %ld.",in_gmt); Log(INFO.buf); for (i=0;i<storage->Meters();i+ + ) { //printf("About to fetch METERID\n"); //fflush(NULL); meterid=0L; try { meterid=kwi->GetMeterlD(iccmid,storage->GetMeterName(i)); } catch(...) { Log(CORBAERR,"Unable to lookup meter id on server."); } //printf("METERID: %ld\n",meterid); //fflush(NULL); if (meterid < 1 L) { Log(CONFERR,"Unable to resolve meter id."); try{ kwi->Log(iccmid,LOG_ERRMETERRESOLVE,"Unable to resolve meter id.",LOGTIME_NOW,LOGjΞRR3); } catch(...) { Log(CORBAERR,"Unable to insert log entry on server."); } } if (storage->Readings(i)) printf(" Inserting Readings (%d):",storage->Readings(i)); else printf(" No Readings to upload\n"); for (j=storage->Readings(i)-1 ;j>=0;j~) { temptime.Set(storage->TimeStamp(i,j)); printfC'."); fflush(NULL); ret=-1 ; try { ret=kwi->lnsertKW( meterid, temptime.Get("simple",NULL 1 0), storage->Reading(i,j), 0L); } catch (...) { Log(CORBAERR,"Error in kwi->lnsertKW()"); } //if (!ret) // { storage->MarkXmitted(i,j); storage->Delete(ij); // } } printf("\n"); fflush(NULL); } newaddminutes=corbaschedule->addminutes; try { newaddminutes=kwi->FetchSchedule(iccmid,"*","*"); } catch(...) { Log(CORBAERR,"Unable to Fetch Commo Schedule from server."); } if (newaddminutes != corbaschedule->addminutes) { corbaschedule->addminutes=newaddminutes; printf("CORBA schedule set to %d minutes.\n",corbaschedule->addminutes); fflush(NULL); WriteMinutesToFile("/tmp/commotry",newaddminutes+15); WriteMinutesToFile("/tmp/commosuccess",(newaddminutes*5)+15); } //upload any pending violations if (watermarks->ViolationCount()) { Log(INFO,"Uploading Watermark Violations"); tempwm=watermarks->GetFirst(); while (tempwm) { try { kwi->Watermark(tempwm->wmid,tempwm->zoneid,tempwm- >wwhen.Get("simple",NULL,0),tempwm->kw); } catch(...) { Log(CORBAERR,"Unable to insert watermark violation on server."); } tempwm=watermarks->GetNext(); } watermarks->ClearViolations(); Log(INFO,"Finished uploading Watermark Violations."); } else Log(INFO,'There were no Watermark Violations to upload."); //printf( ,, \nViolationCount()=%d\n",watermarks->ViolationCount()); notificationcount=OL; try{ notifιcationcount=kwi->GetNotificationCount(iccmid); } catch(...) { Log(CORBAERR,"Unable to fetch notifications;'); } printf("There are %ld notifications to download.\n",notificationcount); if (notificationcount) { Log(INFO,"Downloading Notifications:"); notifs.Lock(42,60); //lock with my identifier for (j=0;j<notificationcount;j++) { tempnotif=new notificationobj; try { kwi->GetNotifιcation(iccmid,j,tempnotif->facility,tempnotif- >code1 ,tempnotif->code2); } catch(...) { Log(CORBAERR,"Error fetching a single notification."); } printf("Just Fetched Notification: %Id, %ld, %ld\n",tempnotif- >faciIity,tempnotif->code1,tempnotif->code2); notifs.notifs.Add(tempnotif); } notifs.UnLock(42); } else Log(INFO,"There were no notifications to download."); //download new kw__client software if necessary if (needupgrade) { //we need an upgrade!!! Log(INFO,"About to fork() for upgrade..."); if ((needupgrade=fork())==0) { Log(INFO,"GoodBye."); sleep(10); if (execlp("/bin/sh","sh" 1 "-c",7usr/local/pepper kwupgrade.sh",NULL)) { Log(INFO,"An error occurred while execl()ing kwupgrade.sh"); perror("errno="); try{ kwi->Log(iccmid,LOGjΞRRUPGRADE,"execl0 error on kwugrade.sh",LOGTIME_NOW,LOG_ERR5); } catch(...) { Log(CORBAERR,"Unable to insert log entry on server."); } } } else { Log(INFO,"GoodBye."); exit(0); //parent should terminate! } //nowload a new meterconfiguration if one exists . struct stat st; if (stat(7etc/pepper/meters",&st)) st.st_mtime=0; //unable to stat /etc/pepper/meters, force download; // printf("iccm update time local: %ld remote: %Id meters:%d\n",st.st_mtime, kwi->GetlCCMUpdate(iccmid), storage->Meters()); try { temptimet= kwi->GetlCCMUpdate(iccmid); } catch(...) { Log(CORBAERR,"Unable to get ICCM updated time from server."); temptimet=0L; } if (st.st_mtime < temptimet) { try{ kwi->Log(0L,LOG_FETCHCONFIG,"Fetching config (meter,watermark,orb,isp).",LOGTIME_NOW,LOGJNFO4); } catch(...) { Log(CORBAERR,"Unable to insert into the server log."); } Log(INFO,"Downloading new meter configuration."); if (!(f 1 =fopen(7etc/pepper/meters","w"))) { Log(CONFERR,"Error writing new /etc/pepper/meters."); } else { try { p1 =kwi->GetMeterConf(iccmid); } catch(...) { Log(CORBAERR,"Error fetching meter config from server."); p1=NULL; } if (pi) fwrite(p1 ,strlen(p1),1 ,f1); fclose(fl); storage->ClearMeters(); if (storage->LoadMeters("/etc/pepper/meters")) Log(CONFERR,"Some meters failed to load (err in /etc/pepper/meters?)"); else Log(INFO,"Finished loading /etc/pepper/meters."); } } if (stat("/etc/pepper/watermarks",&st)) st.st_mtime=0; //unable to stat /etc/pepper/watermarks, force download; if (st.st_mtime < temptimet) { Log(INFO,"Downloading new watermarks."); if (!(f 1 =fopen(7etc/pepper/watermarks","w"))) { Log(CONFERR,"Error writing new /etc/pepper/watermarks."); } else { try{ p1 =kwi->GetWatermarks(iccmid); } catch(...) { Log(CORBAERR,"CORBA Error fetching watermarks."); p1=NULL; } if (p1) fwrite(p1,strlen(p1),1,f1); fclose(f1); if (watermarks->Load ("/etc/pepper/watermarks")) Log(CONFERR,"Some watermarks failed to load (err in /etc/pepper/watermarks?)"); else Log(INFO,"Finished loading /etc/pepper/watermarks."); } } if (stat(7etc/pepper/orbs",&st)) stst_mtime=0; //unable to stat /etc/pepper/orbs, force download; if (st.st_mtime < temptimet) { Log(INFO,"Downloading new orb locations."); if (!(f 1 =fopen(7etc/pepper/orbs","w"))) { Log(CONFERR,"Error writing new /etc/pepper/orbs."); } else { try{ p1 =kwi->GetORBs(iccmid); } catch(...) { Log(CORBAERR,"CORBA Error fetching orbs."); p1=NULL; } if (p1) fwrite(p1,strlen(p1),1,f1); fclose(fl); } } if (stat("/etc/pepper/isps",&st)) st.st_mtime=0; //unable to stat /etc/pepper/isps, force download; if (st.stjTitime < temptimet) { Log(INFO,"Downloading new isps."); if (!(f1 =fopen(7etc/pepper/isps","w"))) { Log(CONFERR,"Error writing new /etc/pepper/isps."); } else { try { p1 =kwi->GetlSPs(iccmid); } catch(...) { Log(CORBAERR,"CORBA Error fetching isps."); p1=NULL; } if (p1) fwrite(p1,strlen(p1),1,f1); fclose(fl); } } Log(INFO,"Exiting CORBATALK0"); try { kwi->Logout(newobj); } catch(...) { Log(CORBAERR,"Unable to finish Logout()."); } try { CORBA::release(kwi); } catch(...) { Log(CORBAERR,"Unable to release kwi."); } try { CORBA::release(prekwi); } catch(...) { Log(CORBAERR,"Unable to release prekwi."); "" } //kwi->_dispose(); Log(INFO,"CORBATALK() exited!"); return(O); } int corbatalkwrapper(char *mac_addr, storageobj * storage, schedulerobj *corbaschedule, watermarksobj *watermarks) { int usingppp; int retval; timej timeout; char *p1; utime(7tmp/commotry",NULL); //touch the times to now usingppp=0; timeout=time(NULL) + 900; //15 minutes retval=-1; if (!fexist(7var/lock corbanet")) { usingppp=1; Log(INFO,"We are using PPP, initiate connection."); killfpid(SIGALRM,7var/lock/callonring.pid"); } else Log(INFO,"Route already exists (ethernet?)"); while (!fexist("/var/lock corbanet") && timeout > time(NULL)) { printf("."); fflush(NULL); sleep(1); } if (timeout < time(NULL)) { Log(PPPERR,"Unable to open PPP link"); p1=new char[16]; memset(p1,0,16); sprintf(p1 ,"PPP Link Failed"); sendlogitems.Add((void *)p1); corbascheduIe->finished(); return(-1); } if (fexist("/var/lock/corbanet")) { printf("Link :-)\n"); sleep(2); retval=corbatalk(mac_addr,storage,corbaschedule,watermarks); } else { p1=new char[50]; memset(p1 ,0,50); strncpy(p1, "Unusual error getting Link (but not a timeout?)",49); sendlogitems.Add((void * )p1); } corbaschedule->finished(); if (usingppp) { killfpid(SIGHUP,"/var/lock/callonring.pid"); } return(retval); } int Log (int code, char Tnsg) { dateobj now; fprintf(stdout,"LOG: %s\t%s (%4.4d)\n",now.Get("simple",NULL,0),msg I code); fflush(NULL); return(O); } int getMACaddr(char * mac_addr, int MAC_LEN) { int fd; struct ifreq si; char *p1; unsigned char buf[32]; char buf2[32]; fd=socket(PFJNET, SOCKjDGRAM, IPPROTOJP); strcpy (si.ifr_name, "ethO"); if (ioctl (fd, SIOCGIFHWADDR, &si) < 0) { return(-2); } memcpy (buf, si.ifr_hwaddr.sa_data, 6); memset(buf2,0,32); sprintf(buf2,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); strcpy(mac_addr,buf2); return(O); / * FILE I ; char buf[255]; char *ptr; memset(mac_addr,0,MACJ-EN); f 1 =fopen(7etc/pepper/mac","r"); if (!f1) { Log(NOMAC,"Unable to open /etc/pepper/mac"); retum(-1); } fgets(buf,254,f1); // while (!(strstr(buf,"ethO"))) // if (fgets(buf,254,f1)==0) II break; ptr=strchr(buf,':'); if (!ptr) Log(NOMAC,"Unable to determine MAC address"); else { ptr-=2; strncpy(mac_addr,ptr, 18); while (isspace(mac_addr[strlen(mac_addr)-1])) mac_addr[strlen(mac_addr)-1]=0; } return(O); 7 } #ifdef USETHREADS //global pthread_mutexj mut = PTHREADj UTEXJNITIALIZER; void *threadlaunch(void *ignore) { sleep(1); if (pthread_mutexJrylock(&mut)) { Log(INFO,"Mutex Locked, Duplcate thread. "); sleep(2); pthread_exit(0); } if (thread_corbaschedule->busy) { Log(INFO,"Duplicate thread exiting (not calling corbatalkQ"); pthread_mutex_unlock(&mut); pthread_exit(0); } thread_corbaschedule->busy=1 ; Log(INFO,"Thread Launched!"); corbatalkwrapper(thread_mac_addr,thread_storage,thread_corbaschedule,threa d_watermarks); Log(INFO,"Thread exiting."); pthread_mutex_unlock(&mut); pthread_exit(0); } #endif int CheckTimedDial() //not being used right now! { FILE *f1 ; int hours; int minutes; char buf[256]; int needtodial; dateobj start, now, dial; if (timed_dial_happened==-1) { //we haven't read the /etc/pepper/timeddial file yet f1=fopen(7etc/pepper/timeddial","r"); if (!f1) { Log(COMMERR,"Unable to open /etc/pepper/timeddial!"); return(-1); } fgets(buf,255,f1); fclose(f1); hours=atoi(buf); minutes=atoi(buf+3); timed_dialjime=(hours*60)+minutes; timed_dial_happened=0; sprintf(buf, "Timed dial should happen %d minutes into each day.",timed_dialjime); Log(INFO.buf); } start. DayStartTimeQ; diaI.Set(start.Get()+(timed_dialJime*60)); if (timed_dial_happened >=0 && (now.GetQ > dial.GetQ) && (now.GetQ- dial.Get() 3600)) timed_dial_happened=0; //reset from day to day if (timed_dial_happened == 0 && (now.GetQ > dial.GetQ) && (now.GetQ- dial.GetO < 3600)) needtodial=(now.Get()-dial.Get())/60; //minutes ago we should have dialed else needtodial=0; #ifdef USETHREADS if (thread_corbaschedule->busy==1) { if (needtodiaI> 15) { Log(INFO,"corbaschedule is still busy, so we are going to override it."); thread_corbaschedule->busy=0; signalpoll=1; timed_dial_happened=1 ; } else { Log(INFO,"We need to do our dialy timed dial, but corbaschedule is busy : ("); retum(O); } } #endif Log(INFO,"lt is time to do our dialy timed dial."); signalpoll=1; timed_dial_happened=1 ; return(O); } int setTZO { FILE 71; char buf[255]; char *ptr; f1=fopen("/etc/pepper/timezone","r"); if (!f1) { Log(TIMEERR,"Unable to open /etc/pepper/timezone"); return(-1); } sprintf(buf,"TZ="); fgets(buf+3,251 ,f1); while (isspace(buf[strien(buf)-1 ])) buf[strlen(buf)-1]=0; if (strlen(buf) >= 6) putenv(buf); else Log(TlMEERR,"TZ is too short, not setting."); return(O); } main(int argc, char **argv) { schedulerobj *pollschedule; schedulerobj *corbascheduIe; storageobj *storage; watermarksobj watermarks; char mac_addr[64]; int cycles; char buf[256]; char * p1; int i; notificationobj * tempnotif; int usetemplogs; WriteMinutesToFileC'/tmp/commotry", 15); WriteMinutesToFile("/tmp/commosuccess",45); if (getenv("OMNIORB_CONFIG")==NULL) putenv("OMNIORB_CONFIG=/etc/omniORB.cfg"); cycles=9; fιrstcommo=1; commandargcount=argc; commandargs=argv; //memcpy(commandargs,argv,(sizeof(char *)argc)); setTZQ; p1=NULL; suppressupgrades=0; usetemplogs=0; for (i=1;i<argc;i++) { p1=argv[i]; if (strcmp(p1 ,"-testtube")==0) { Log(INFO,"This was a testtube execution. Exiting..."); exit(99); } if (strcmp(p1,"-L")==0) { memset(argvlog, 0,256); strncpy(argvIog,argv[i+1],255); } if (strcmp(p1 ,"-U")==0) suppressupgrades=30; if (strcmp(p1 ,"-v")==0) printf("kw_client %s (%ld)\ncopyright 1999,2000 by Stonewater Software, lnc.\n\n",VERSION_HUMAN,(unsigned long)VERSION_CODIFIED); if (strcmp(p1 ,"-V")==0) { printf("kw_client %s (%ld)\ncopyright 1999,2000 by Stonewater Software, lnc.\n\n",VERSION_HUMAN,(unsigned long)VERSION_CODIFlED); exit(0); } if (strcmp(p1,"-t")==0) usetemplogs=1 ; } #ifdef USETHREADS spaboard=new spa2; spaboard->connect(); #endif storage=NULL; signalpoll=0; signal(SIGHUP,onhup); getMACaddr(mac_addr,64); printfC'Starting with MAC address: %s\n",mac_addr); timed_dial_happened=-1 ; //we haven't read the /etc/pepper/timedial file yet if (!(storage=new storageobj)) { Log(OUTMEM,"Unable to create storage obj...exiting"); exit(1); } if (!(pollschedule=new schedulerobj)) { Log(OUTMEM,"Unable to create POLL scheduler...exiting"); exit(1); } if (!(corbaschedule=new schedulerobj)) { Log(OUTMEM,"Unable to create CORBA scheduler...exiting\n"); exit(1); } #ifdef USETHREADS pthreadj corbathread; thread_mac_addr=mac_addr; thread_storage=storage; thread_corbaschedule=corbaschedule; thread_watermarks=&watermarks; pthread_create(&corbathread,NULL,threadlaunch,NULL); pthread_detach(corbathread); #else corbatalkwrapper(mac_addr,storage,corbaschedule,&watermarks); #endif //corbaschedule->finished(); //this func now called inside corbatalkQ!!! if (storage->Meters()==0) { if (storage->LoadMeters("/etc/pepper/meters")) { Log(CONFERR,"Some meters failed to load (error in /etc/pepper/meters?)"); } } if (polIschedule->Load("poll")) { Log(NOPOLLSCH,"Unable to load POLL schedule...exiting\n"); exit(1); } if (corbaschedule->Load("corba")) { Log(NOCORBASCH,"Unable to load CORBA schedule...exiting\n"); exit(1); } if (watermarks.Load(7etc/pepper/watermarks")) Log(CONFERR,"Some watermarks failed to load (err in /etc/pepper/watermarks?)") ; else Log(INFO,"Finished loading /etc/pepper/watermarks."); while (1) { //fprintf(stderr,"+"); if (usetemplogs && (cycles % 10 ==0)) { freopen("/tmp/kw","w",stdout); } storage->Poll(); //poll all meters // CheckTimedDialQ; killfpid(SIGPROF,"/var/lock swatchdog.pid"); storage->CheckWatermarks(&watermarks); if (watermarks .ViolationCountQ) { Log(INFO,"Because Watermark Violations exist, we are initiating corbatalk()."); corbaschedule->Later(0); //we need to upload the violations! } if (signalpoll) { corbaschedule->Later(0); //now! signalpoll=0; } if ((corbaschedule->istime() && !corbaschedule->busy)) { #ifdef USETHREADS pthread corbathread; thread_mac_addr=mac_addr; thread_storage=storage; thread_corbaschedule=corbaschedule; thread_watermarks=&watermarks; //need to do this quickly to avoid many corbatalkQ threads signalpoll=0; sleep(1); pthread_create(&corbathread,NULL,threadlaunch,NULL); pthread_detach(corbathread); #else if (storage->PollSoon(3)) { Log(INFO,"One or meters are going to poll within 3 minutes, corbatalkQ deferred for 4 minutes."); corbaschedule->Later(4); //push 4 minutes into the future } else { corbatalkwrapper(mac_addr,storage,corbaschedule, &watermarks); //corbaschedule->finished(); //this call moved into corbatalkQ signalpoll=0; } #endif } else { #ifdef USETHREADS if (notifs.Lock(13,60)==0) //lock the notification collection with this thread's lock code (13) { for (i=0;i<notifs.Count();i++) { tempnotif=notifs.ltem(i); if (tempnotif) spaboard->activate((unsigned long)tempnotif->facility,(unsigned long)tempnotif->code1.(unsigned long)tempnotif->code2,0L); else Log(INFO,"Error accessing one of the notification items."); } notifs.RemoveAIIQ; notifs.UnLock(13); } cycles++; if (cycles % 10 ==0) { corbaschedule->istime("corba"); //Log(INFO,"Trying to Poll the Green Button."); cycles=0; spaboard->housekeep(); } else sleep(1); if (spaboard->buttons || spaboard->chirps) { sprintf(buf,"Buttons: %d, Chirps: %d\n",spaboard->buttons,spaboard- >chirps); spaboard->buttons=0; spaboard->chirps=0; p1=new char[strlen(buf)+1]; strcpy(p1,buf); sendlogitems.Add((void *)p1); corbaschedule->Later(0); } #else sleep(1); #endif } } exit(0); } #define CONTEXTNAMEID "stonergy" #define CONTEXTNAMEKIND "context" #define NAMEID "kwjnserter" #define NAMEKIND "Object" static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb) { CosNaming::NamingContext_var rootContext; try { // Obtain a reference to the root context of the Name service: CORBA::Object_var initServ; printf("\tA\n"); fflush(NULL); initServ = orb->resolveJnitial_references("NameService"); // Narrow the object returned by resolveJnitial_references() //to a CosNaming::NamingContext object: printf("\tB\n"); fflush(NULL); rootContext CosNaming::NamingContext::_narrow(initServ); if (CORBA: :is_nil(rootContext)) { cerr « "Failed to narrow naming context." « endl; return CORBA::Object::_nil(); } } // catch(CORBA::ORB::lnva!idName& ex) { catch(...) { cerr « "Service required is invalid [does not exist] ' « endl; return 0; } printf("\tC\n"); fflush(NULL); CosNaming::Name contextName; contextName.length(2); contextName[0].id = (const char*) CONTEXTNAMEID; // string copied contextName[0].kind = (const char * ) CONTEXTNAMEKIND; // string copied contextName[1].id = (const char*) NAMEID; // string copied contextName[1].kind = (const char*) NAMEKIND; // string copied CORBA::Object_ptr obj; printf("\tD\n"); fflush(NULL); try { obj=rootContext->resolve(contextName); } catch (...) { cerr« "Caught a fatal exception in COS Naming Service"«endl; return CORBA::Object::_nil(); } printf("\tE\n"); fflush(NULL); return obj; } FILE: dbifaceobj.h encapsulates the database connectivity required by the server side of the corba implementation . #ifndef_DBIFACEOBJ_H #define _DBIFACEOBJ_H #include "stdincludes.h" #include "dateobj. h" #include "collectionbase.h" #include "keyring. h" #include "libpq++.h" #include "stonergy_defs.h" #include "../sib/kw_client/logcodes.h" #ifndef MAXULONG #define MAXULONG Oxffffffff #endif class DBIFACEObj { public: DBIFACEObJO; -DBIFACEObjQ; int UsableQ; char *GetTableKey(long zoneid, long moduleid, long keyid, char *dest, int destlen); long SetTableKey(long zoneid, long moduleid, long keyid, const char * val); long FindlCCM(const char *HWADDR); long GetZoneParent(unsigned long zoneid); long FindHWKey(const char *HWADDR); long GetlCCMMeterByName(unsigned long iccmzoneid, const char * metername); int Archive(dateobj *startdate, dateobj *enddate, long Meterld); long ArbitrarySQL(char * qrystr); int lnsertKW(unsigned long zoneid, dateobj * wwhen, float KW, unsigned long scenario=0L); long GetZoneBySource(long ancestorid, const char * meter_number); long Log(long userid, long zoneid, char * when, char * action, long severity); long GetlCCMUpdate(long iccmid); long GetMeterConf(long iccmid, char * conf); long GetCommoSchedule(long iccmid); long lnsertWatermark(unsigned long wmid, dateobj * temp, float KW); long GetWatermarks(unsigned long zoneid, char * buf); long GetlSPs(unsigned long zoneid, char *buf); long GetORBs(unsigned long zoneid, char *buf); long GetNotificationCount(unsigned long zoneid); long GetNotification(long zoneid, long which, long &facility, long &code1, long &code2); long SendEmail(unsigned long zoneid, const char *message, const char *subject=NULL); protected: bool status; //pglib boolean //PgEnv env; PgDatabase * db; //PgCursor *data; PgDatabase *data; int needDoneQuery; PgCursor *NewQuery(const char *inqrystr); int EndQuery(PgCursor *tempdata); long RunQuery(char * inqrystr); int DoneQueryQ; unsigned long DBIFACEObj::GetSequence(const char *seqname); }; #endif FILE: dbifaceobj.cxx implementation file for the database interface #include "dbifaceobj.h" #include "notifier.h" //protected stuff : /*long DBIFACEObj::RunQuery(char *inqrystr) { char qrystr[2048]; // printf("============= Run Query =============\n"); if (needDoneQuery) DoneQueryO; needDoneQuery=1 ; sprintf(qrystr,"DECLARE ceces%ldcur CURSOR FOR %s",getpidQ,inqrystr); if (status=data->Exec("begin transaction") != PGRES_COMMAND_OK) { fprintf(stderr,"BEGIN command failed\n"); data->Exec("end transaction"); needDoneQuery=0; return(-IL); } status=data->Exec(qrystr); if (status != PGRES_COMMAND_OK && status!= PGRES_EMPTY_QUERY) { fprintf(stderr,"DECLARE CURSOR command failed (status=%d): \n(%s)\n",status,qrystr); needDoneQuery=0; return(-2); } // printf("status=%d\n",status); if (status==PGRES_EMPTY_QUERY) { printf("Empty queryΛn"); needDoneQuery=0; return(OL); } sprintf(qrystr,"FETCH ALL in ceces%ldcur",getpidQ); if (status=data->Exec(qrystr) != PGRES_TUPLES_OK) { fprintf(stderr,"FETCH ALL command didn't return tuples properly\n"); needDoneQuery=0; retum(-3); } return(data->TuplesQ); } int DBIFACEObj::DoneQuery() { char qrystr[1024]; int tries; if (IneedDoneQuery) return(O); needDoneQuery=0; sprintf(qrystr,"CLOSE ceces%Idcur",getpidQ); data->Exec(qrystr); data->Exec("end transaction"); return(O); } 7 PgCursor *DBIFACEObj::NewQuery(const char *inqrystr) { char qrystr[2048]; int tries; int localstatus; dateobj now; char cursorname[256]; PgCursor *tempdata; sprintf(cursorname,"c%ld_%ld_%ld",getpid(), now.GetQ, randomQ); tempdata=new PgCursor((const char * )"dbname=stonergy",(const char * )cursorname); if (tempdata->ConnectionBadQ) { printf("Error connecting to database!\n"); return(NULL); } tries=0; localstatus=0; while (ϋocalstatus && tries < 100) { tries++; Iocalstatus=tempdata->Declare(inqrystr); if (ϋocalstatus) sleep(1); } if (ϋocalstatus) { fprintf(stderr,"DECLARE CURSOR command failed (status=%d): \n(%s)\n",status ,q rystr) ; return(NULL); } localstatus=tempdata->Fetch(); if (ϋocalstatus) { fprintf(stderr,"FETCH ALL command didn't return tuples proper!y\n"); return(NULL); } retum(tempdata); } int DBIFACEObj::EndQuery(PgCursor *tempdata) { if (tempdata) { tempdata->Close(); delete tempdata; } return(O); } /*long DBIFACEObj::RunQuery(char *inqrystr) { char qrystr[2048]; int tries; if (needDoneQuery) DoneQueryQ; needDoneQuery=1 ; tries=0; status=0; while (istatus && tries < 100) { tries++; status=data->Declare(inqrystr); if (Istatus) sleep(1); } if (istatus) // != PGRES_COMMAND_OK && status!= PGRES_EMPTY_QUERY) { fprintf(stderr,"DECLARE CURSOR command failed (status=%d): \n(%s)\n",status,qrystr); needDoneQuery=0; retum(-2); } if (status==PGRES_EMPTY_QUERY) { printf("Empty queryΛn"); needDoneQuery=0; return(OL); } status=data->Fetch(); if (istatus) //=data->Exec(qrystr) != PGRES_TUPLES_OK) { fprintf(stderr,"FETCH ALL command didn't return tuples properlyW); needDoneQuery=0;- return(-3); } return(data->TuplesQ); } int DBIFACEObj::DoneQuery() { char qrystr[1024]; if (JneedDoneQuery) retum(O); needDoneQuery=0; data->Close(); return(O); } 7 long DBIFACEObj::RunQuery(char *inqrystr) { char qrystr[2048]; int tries; DoneQueryQ; needDoneQuery=1 ; tries=0; status=0; status=data->Exec(inqrystr); if (istatus) //data->Exec(qrystr) != PGRES_TUPLES_OK) { fprintf(stderr,"Exec() didn't return tuples properly\n"); needDoneQuery=0; return(-3); } return(data->TuplesQ); } int DBIFACEObj::DoneQuery() { char qrystr[1024]; if (ineedDoneQuery) retum(O); needDoneQuery=0; //data->Close(); return(O); } unsigned long DBIFACEObj::GetSequence(const char * seqname) { char qrystr[2048]; unsigned long tempjd; sprintf(qrystr,"select nextval('%s')",seqname); RunQuery(qrystr); tempJd=atol(data->GetValue(0,0)); DoneQueryQ; retum(tempjd); } int DBIFACEObj::Usable() { return(!data->ConnectionBadQ); } DBIFACEObj-DBIFACEObJO { dateobj now; char cursorname[256]; sprintf(cursorname,"c%ld_%id_%ld",getpid(), now.GetQ, randomQ); data=new PgDatabase("dbname=stonergy"); //db=new PgDatabase((const char * )"dbname=stonergy"); db=data; //data=new PgCursor((const char *)"dbname=stonergy",(const char *)cursomame); if (data->ConnectionBadQ) { printf("Error connecting to database!\n"); } needDoneQuery=0; } DBIFACEObj::~DBIFACEObj() { DoneQueryO; //if (db) // { // delete db; } if (data) delete data; } long DBIFACEObj::GetZoneBySource(long ancestorid, const char *meter_number) { char *p1, * p2,*p3; char qrystr[2048]; char temp[2048]; long ret; if (meter_number==NULL) return(OL); //note: this is not yet truly an ancestor id (only a prentid). //an skey (:4:23:112:2213:) would make an ancestor search very easy! sprintf(qrystr,"select * from zones where (source='%s' and parentid=%ld) where active order by priority",meter_number, ancestorid); RunQuery(qrystr); if (!data->TuplesQ) return(OL); ret=atol(data->GetValue(0,"zoneid")); DoneQueryQ; return(ret); } long DBIFACEObj::FindlCCM(const char *HWADDR) { char qrystr[2048]; unsigned long temp; PgCursor *tempdata; sprintf(qrystr,"select * from iccm where (hwaddr='%s')",HWADDR); // printf("%s\n",qrystr); //tempdata=NewQuery(qrystr); RunQuery(qrystr); if (!data->TuplesQ) retum(OL); temp=atol(data->GetValue(0,"zoneid")); //EndQuery(tempdata); DoneQueryQ; Log(LOG_HWLOGIN,temp,"now","HWLogin",1); return(temp); } long DBIFACEObj::GetlCCMMeterByName(unsigned long iccmzoneid, const char * metername) { charqrystr[2048]; unsigned long temp; sprintf(qrystr,"select * from iccmmeters where (iccmzoneid=%ld and alias='%s')" ) iccmzoneid,metername); // printf("%s\n",qrystr); RunQuery(qrystr); if (!data->Tuples()) return(MAXULONG); temp=atol(data->GetValue(0,"meterzoneid")); DoneQueryQ; returnrtemp); } long DBIFACEObj::GetZoneParent(unsigned long zoneid) { char qrystr[2048]; unsigned long temp; sprintf(qrystr,"select * from zones where (zoneid=%ld)",zoneid); RunQuery(qrystr); if (!data->Tuples()) return(MAXULONG); temp=atol(data->GetValue(0,"parentid")); DoneQueryQ; return(temp); } long DBIFACEObj::FindHWKey(const char *HWADDR) { char qrystr[2048]; unsigned long temp; sprintf(qrystr,"select * from keys where (moduleid=%ld and keyid=%ld)",MODULE_KWJNSERTER,KEY_HWADDR); RunQuery(qrystr); if (!data->TuplesQ) return(OL); temp=atol(data->GetValue(0,"value")); DoneQueryQ; retumftemp); } char *DBIFACEObj::GetTableKey(long zoneid, long moduleid, long keyid, char *dest, int destlen) { char qrystr[2038]; sprintf(qrystr, "select * from keys where (zoneid=%d and scenario=0 and moduleid=%ld and keyid=%ld)",zoneid, moduleid, keyid); //printf("%s — ",qrystr); RunQuery(qrystr); if (!data->TuplesQ) return(dest); strncpy(dest,data->GetVaIue(0,"keyval"),destlen); //printf("%s\n",dest);fflush(NULL); DoneQueryO; return(dest); } long DBIFACEObj::SetTableKey(long zoneid, long moduleid, long keyid, const char *val) { char qrystr[2038]; long status; sprintf(qrystr,"select * from keys where (zoneid=%d and scenario=0 and moduleid=%ld and keyid=%Id)",zoneid, moduleid, keyid); RunQuery(qrystr); status=data->Tuples(); DoneQueryQ; //if (!data->TuplesQ) // return(dest); if (status > 0) { sprintf(qrystr,"update keys set keyval- %s' where (zoneid=%ld and scenario=0 and moduleid=%ld and keyid=%ld)",val,zoneid, moduleid, keyid); // printf("%s\n",qrystr); if (!db->ExecCommandOk((const char *)qrystr)) printf("Error pg_exec()ing query: %s\n\n",qrystr); } else { sprintf(qrystr,"insert into keys values (%ld,%ld,0,%ld,'%s')",zoneid,moduleid,keyidNal); // printf("%s\n",qrystr); data-> Exec(q rystr) ; } return(OL); } int DBIFACEObj::Archive(dateobj *startdate, dateobj *enddate, long Meterld) { char qrystr[2048]; memset(qrystr,0,2048); sprintf(qrystr, "delete from readings where (wwhen between '%s' and '%s' ", startdate->Get("simple",NULL,0),enddate->Get("simple",NULL,0)); if (JMeterld) strcat(qrystr,")"); else sprintf(qrystr+strlen(qrystr)," and zoneid=%ld",Meterld); data-> Exec(q rystr) ; return(O); } long DBIFACEObj::Log(long userid, long zoneid, char *when, char *action, long severity) { char bufJ256]; sprintf(buf,"insert into log values (%ld,%ld,'%s','%s',%ld)", userid, zoneid, when, action, severity); data->Exec(buf); printf("DBIFACE LOG: %s\n",buf); fflush(NULL); return(OL); } long DBIFACEObj::ArbitrarySQL(char *qrystr) { data-> Exec(q rystr) ; return(OL); } int DBIFACEObj::lnsertKW(unsigned.long zoneid, dateobj *wwhen, float KW, unsigned long scenario) { char qrystr[2048]; sprintf(qrystr, "insert into readings (zoneid, wwhen, reading) values (%ld,'%s',%2.2fO)",zoneid,wwhen->Get("simpIe",NULL,0),KW); //maybe we should be doing some data validation...meter validation...etc // printf("%s\n",qrystr); fflush(NULL); if (!db->ExecCommandOk((const char *)qrystr)) printf("Error pg_exec()ing query: %s\n\n",q rystr); return(O); } long DBIFACEObj::GetlCCMUpdate(long iccmid) { char qrystr[2048]; timej tempj; dateobj temp_d; sprintf(qrystr, "select * from iccm where zoneid=%ld",iccmid); // printf("%s\n",qrystr); fflush(NULL); RunQuery(qrystr); if (!data->TuplesQ) return(OL); temp_d.Set(data->GetValue(0,"updated"),"timestamp"); // printf("%s\t%s\n",data- >GetValue(0,"updated"),temp_d.Get("simple",NULL,0)); tempJ=temp_d.Get(); DoneQueryQ; return(tempj); } long DBIFACEObj::GetMeterConf(long iccmid, char * conf) { //copies a configuration line into confline char buf[256]; char qrystr[2048]; char metertype[64]; int i; dateobj tempdate; sprintf(qrystr,"select * from iccmmeters where iccmzoneid=%ld",iccmid); // printf("%s\n",qrystr); fflush(NULL); RunQuery(qrγstr); if (!data->TuplesQ). { conf=NULL; return(-1); } sprintf(buf,"#Meter configuration downloaded at %s\n\n",tempdate.Get("simple",NULL,0)); strcat(conf,buf); for (i=0;i<data->Tuples();i++) { memset(buf,0,256); memset(metertype,0,64); // switch (atol(data->GetValue(i,"mtype"))) // { // case 10: //random 1 // sprintf(metertype,"random1"); // break; // case 20: //newyorkpulsel // sprintf(metertype,"newyorkpulse1 "); // break; // default: // sprintf(metertype,"random1"); // } sprintf(buf,"%ld:%s:%s:%d:%2.2f:%s\n", atol(data->GetValue(i,"meterzoneid")), data->GetValue(i,"alias"), data->GetValue(i,"mtype") , atoi(data->GetVaIue(i,"minutes")), atof(data->GetVaIue(i,"multiplier")), data->GetValue(i,"misc")); strcat(conf.buf); } sprintf(buf,"\n\n"); strcat(conf.buf); DoneQueryQ; retum(O); } long DBIFACEObj::GetCommoSchedule(long iccmid) { long minutes.tempminutes; char qrystr[2048]; sprintf(qrystr,"select * from iccm where zoneid=%ld",iccmid); // printf("%s\n",qrystr); fflush(NULL); RunQuery(qrystr); if (!data->TuplesQ) { return(OL); } tempminutes=atol(data->GetValue(0,"tempschedule")); minutes=atol(data->GetValue(0,"commoschedule")); DoneQueryQ; return((tempminutes<minutes)?tempminutes:minutes); } long DBlFACEObj::lnsertWatermark(unsigned long wmid, dateobj * temp, float KW) { char qrystr[2048]; sprintf(qrystr,"insert into hilolog values (%ld,'%s',%2.2f0)",wmid,temp- >Get("simple",NULL,0),KW); printf("lnserting Watermark: %s\n",qrystr); fflush(NULL); data->Exec(qrystr); return(OL); } long DBIFACEObj::GetWatermarks(unsigned long zoneid, char * conf) { char buf[256]; char qrystr[2048]; char wtype[64]; int i; dateobj tempdate; sprintf(qrystr,"select * from hilowat where (zoneid=%ld or zoneid in (select zoneid from zones where (parentid=%ld)) and active) order by seq",zoneid,zoneid); // printf("%s\n",qrystr); fflush(NULL); RunQuery(qrystr); if (!data->TuplesQ) { conf=NULL; return(-1); } sprintf(buf,"#Watermarks downloaded at %s\n\n",tempdate.Get("simple",NULL,0)); strcat(conf.buf); for (i=0;i<data->Tuples();i++) { memset(buf,0,256); memset(wtype,0,64); switch(atoi(data->GetValue(i,"wtype"))) { case HI WATER: sprintf(wtype,"HI"); break; case LOWATER: sprintf(wtype,"LO"); break; case EQWATER: sprintf(wtype,"EQ"); break; case LOWATERNZ: sprintf(wtype,"LONZ"); break; default: sprintf(wtype,"HI"); } sprintf(buf,"%ld:%ld:%s:%2.2f:%s\n", atol(data->GetValue(i,"id")), atol(data->GetValue(i,"zoneid")), wtype, atof(data->GetValue(i, "watermark")), data->GetValue(i,"suspect")); strcat(conf,buf); } sprintf(buf,"\n\n"); strcat(conf,buf); DoneQueryQ; return(O); } long DBIFACEObj::GetlSPs(unsigned long zoneid, char *conf) { char buf[256]; char qrystr[2048]; int i; dateobj tempdate; char predial[32]; int iccmareacode; memset(predial,0,32); iccmareacode=0; sprintf(qrystr,"select * from iccm where zoneid=%ld",zoneid); RunQuery(qrystr); if (!data->Tuples()) printf("::GetlSPs() Unable to lookup ICCM zoneid (%ld)\n",zoneid); else { strncpy(predial,data->GetValue(0,"dialprefix"),31); iccmareacode=atoi(data->GetValue(0,"areacode")); DoneQueryQ; } sprintf(qrystr,"select * from zoneisps, isps where (zoneid=%ld and zoneisps.ispid=isps.ispid and isps.active and zoneisps.active) order by priority",zoneid); printf("%s\n",qrystr); fflush(NULL); RunQuery(q rystr); if (!data->TuplesQ) { conf=NULL; return(-1); } sprintf(buf,"#ISPs downloaded at %s\n\n",tempdate.Get("simple",NULL,0)); strcat(conf.buf); printf(conf); fflush(NULL); for (i=0;i<data->Tuples();i++) { memset(buf , 0 ,256) ; if (atoi(data->GetValue(i,"areacode")) !=iccmareacode) //userid:passwd:phone sprintf(buf,"%s:%s:%s1 %s%s\n", data->GetValue(i,"userid"), data->GetVal ue(i ,"passwd") , (strlen(predial)?predial:""), data->GetValue(i,"areacode"), data->GetValue(i,"phone")); else //userid :passwd: phone sρrintf(buf,"%s:%s:%s%s\n", data->GetValue(i,"userid"), data->GetValue(i,"passwd"), (strlen(predial)?predial:""), data->GetValue(i,"phone")); printf("%s",buf); fflush(NULL); strcat(conf,buf); } sprintf(buf,"\n\n"); strcat(conf,buf); DoneQueryO; printf("\nExiting ::GetlSPs()\n"); fflush(NULL); return(OL); } long DBIFACEObj::GetORBs(unsigned long zoneid, char * conf) { char buf[256]; char qrystr[2048]; char wtype[64]; int i; dateobj tempdate; sprintf(q rystr, "select * from zoneorbs, orbs (zoneid=%ld and zoneorbs.orbid=orbs.orbid and zoneorbs. active and orbs.active) order by zoneorbs. priority",zoneid); // printf("%s\n",qrystr); fflush(NULL); RunQuery(qrystr); if (!data->TuplesQ) { conf=NULL; retum(-1); } sprintf(buf,"#ORBs downloaded at %s\n\n",tempdate.Get("simple",NULL,0)); strcat(conf,buf); for (i=0;i<data->Tuples();i++) { memset(buf,0,256); sprintf(buf,"%ld:%sJ/os\n", atol(data->GetValue(i,"id")), data->GetValue(i,"ip"), data->GetValue(i,"port")); strcat(conf,buf); } sprintf(buf,"\n\n"); strcat(conf,buf); DoneQueryQ; return(O); } long DBIFACEObj::GetNotifιcationCount(unsigned long zoneid) { char qrystr[2048]; long i; sprintf(qrystr,"select count(*) from notifymessages where (zoneid=%ld and senttime='epoch')",zoneid); printf("%s\n",qrystr); fflush(NULL); RunQuery(qrystr); if (!data->TuplesQ) { retum(-1); } i=atol(data->GetValue(0,0)); DoneQueryQ; return(i); } long DBIFACEObj::GetNotification(long zoneid, long which, long &facility, long &code1 , long &code2) { char qrystr[2048]; long i; sprintf(qrystr,"select * from notifymessages where (zoneid=%ld and senttime='epoch') order by starttime",zoneid); RunQuery(q rystr); if (!data->TuplesQ) { printfC'No Tuples\n"); return(-1); } if (which < 0 || which >= data->TuplesQ) { printffMessage out of bounds\n"); DoneQueryQ; return(-2); } facility=atol(data->GetValue(which,"facility")) codel =atol(data->GetValue(which,"code1 ")) code2=atol(data->GetValue(which,"code2")) sprintf(qrystr,"update notifymessages set senttime=now() where (zoneid=%ld and starttime='%s' and facility=%s)",zoneid,data- >GetValue(which,"starttime"),data->GetValue(which,"facility")); printf("%s\n",qrystr); fflush(NULL); DoneQuery(); d ata-> Exec(q rystr) ; return(O); } long DBIFACEObj::SendEmail(unsigned long zoneid, const char Tnessage, const char *subject) { notifierobj email; char recipient[256]; char qrystr[2048]; int i; sprintf(qrystr,"select * from notify where ((zoneid=%ld or zoneid in (select zoneid from zones where zpath like '%%:%s:%%'))and (method=%d or method=%d or method=%d) and active and curtail)",zoneid, zoneid, NOTIF_EMAlL,NOTIF_PAGER,NOTlF_FAX); RunQuery(qrystr); if (!data->Tuples()) { return(-1); } for (i=0;i<data->Tupies();i++) { memset(recipient,0,256); strcpy(recipient,data->GetValue(i,"address")); email.SendEmail("127.0.0.1",recipient,"ENERGY',subject,message); } DoneQueryQ; return(O); } FILE: iccm_client.h. Header for client.cxx #ifndef _ICCM_CLIENT_H #define _ICCM_CLIENT _H #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <iostream.h> #include <ctype.h> #include <sys/types.h> #include <utime.h> #include "dateobj.h" #include "meterdrivers/drivers.h" #include "meterdrivers/meterobj.h" #incIude "common/collectionbase.h" #include "stonergy_defs.h" #define VERSION_CODIFIED 0x00000209 #define VERSION HUMAN "vO.0.2.9" #define USENAMES #define VEND_STONEWATER 1 L #defιne TYPE_MISC 0L //define local log conditions #define NOMAC 31 #defιne OUTMEM 32 #define NOPOLLSCH 33 #define NOCORBASCH 34 #define NOCONF 35 #define CONFERR 36 #define PIDERR 37 #define CORBAERR 38 #define INFO 39 #define PPPERR 40 #define COMMERR 41 #define TIMEERR 42 #ifndef MAXULONG #define MAXULONG Oxffffffff #endif int Log (int code, char *msg); class storageobj; class schedulerobj; #endif FILE: divclient.cxx entry point in kw_client for connecting to the orb and getting the object reference for the other side. ============================================================ */ #include <stdio.h> #include <stdlib.h> #include <iostream.h> #include "omnithread.h" #include "kwjnserter.hh" #include "dateobj. h" #define USENAMES #define VEND_STONEWATER 1L #define TYPE_MISC 0L static CORBA: :Object_ptr getObjectReference(CORBA::ORB_ptr orb); main(int argc, char **argv) { CORBA::ORB_ptr orb; CORBA::BOA_ptr _myboa; kw_inserter_var myobjRef; kwjnserter *kwi; orb=CORBA::ORBJnit(argc, argv,"omniORB2"); _myboa=orb->BOAJnit(argc, argv,"omniORB2_BOA"); CORBA: :Object_var obj; #ifdef USENAMES try { obj=getObjectReference(orb); } catch(...) { cerr«"Error connecting to to CORBA object."«endl; exit(1); } #endif if (CORBA::is_nil(obj)) printf("obj says that it is _nil()\n"); kwi=kwJnserter::_narrow(obj); if (CORBA: :is_nil(kwi)) printf("After _narrow, kwi says that it is _nil()\n"); if (argc<7) { printf("usage: divclient zoneid secret start-date-time end-date-time demand consumption\n"); exit(1); } float temp.individual.added; float kw.kwh; long inserted; dateobj start, end, begun, ended; int needchunks.i; kwi->Login(atol(argv[1]),argv[2]); begun. NowQ; start.Set(argv[3],"simple"); end.Set(argv[4],"simple"); kw=atof(argv[5]); kwh=atof(argv[6]); if (!kw || !kwh) { printf("Both consumption and demand must be greater than zero!\n\n"); exit(1); } inserted=1L; //needchunks=(kwh-(kw/2)) / (kw); //could use (kw/2)+1, but why push it? added=kw/2; kwi->lnsertKW(atol(argv[1]),start.Get("simple",NULL,0),kw/2,0L); //demand individual=((kwh-(kw/2)) / (kwh / ((kw/2)-5))); //-5 is fudge factor //for (i=1 ;i<needchunks;i++) while (added < kwh) { start.Add(1800); if (kwh - added < individual) kwi->lnsertKW(atol(argv[1]),start.Get("simple",NULL,0),kwh-added,0L); else kwi->lnsertKW(atol(argv[1]),start.Get("simple",NULL,0),individual,0L); inserted++; added+=individual; //this is ok that added will be too large on last loop } ended. Now(); printf("lnserted %ld records in %ld seconds (%ld inserted / second)\n\n" I inserted,ended.Get()-begun.Get(),inserted/(ended.GetQ- begun.GetQ)); exit(0); } #define CONTEXTNAMEID "stonergy" #define CONTEXTNAMEKIND "context" #define NAMEID "kwjnserter" #define NAMEKIND Object" static CORBA: :Object_ptr getObjectReference(CORBA::ORB_ptr orb) { CosNaming::NamingContext_var rootContext; try { // Obtain a reference to the root context of the Name service: CORBA::Object_var initServ; initServ = orb->resolveJnitiaI_references("NameService"); // Narrow the object returned by resolveJnitial_references() //to a CosNaming::NamingContext object: rootContext = CosNaming::NamingContext::_narrow(initServ); if (CORBA::is_nil(rootContext)) { cerr « "Failed to narrow naming context" « endl; return CORBA.:Object::_nil(); } } catch(CORBA::ORB::lnvalidName& ex) { cerr « "Service required is invalid [does not exist]." « endl; return 0; } // Bind a context called "test" to the root context: CosNaming::Name contextName; contextName.length(2); contextName[0].id = (const char * ) CONTEXTNAMEID; // string copied cαntextName[0].kind = (const char*) CONTEXTNAMEKIND; // string copied contextName[1].id = (const char*) NAMEID; // string copied contextName[1].kind = (const char*) NAMEKIND; // string copied CORBA: :Object_ptr obj; try { obj=rootContext->resolve(contextName); } catch (...) { cerr« "Caught a fatal exception in COS Naming Service"«endl; return CORBA::Object::_nil(); } return obj; } FILE: installer.c a program for gathering configuration information before we install new software on the iccm. Also creates scripts for setting up iccm configuration and start up scripts =7 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> typedef struct install { int isethemet; int isdhcp; int glibc; char modempath[64]; long modemspeed; int callonring; //0== use -o to suppress callonring char spapath[64]; int server; //1=buster, 2=chloe, etc char mac[64J; char hostname[128]; } installstruct; AskAway(installstruct *inst) { char buf[256]; int i; char *p1; memset(buf,0,256); printf("Which C Lib do you use (20=GLIBC2.0, 21=GLIBC2.1)? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) *p1=0; inst->glibc=atoi(buf); memset(inst->hostname,0,256); printf("Enter a hostname for this ICCM: "); fgets(inst->hostname,127,stdin); memset(buf,0,256); printf("ls this an Ethernet customer [y/N]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) * p1=0; if (strlen(buf)==0 || buf[0]=='N' || buf[0]== * n') inst->isethernet=0; else { printf("ls this a DHCP customer [Y/n]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) * p1=0; if (strlen(buf)==0 || buf[0]=='N * || buf[0]== * n') printf("You must configure the ICCM IP address and network information by hand according to information from the Customer's IS staff!\n"); else inst->isdhcp=1; inst->isethernet=1; } memset(buf,0,256); printf("What serial port is the modem on [/dev/modem]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) *p1=0; if (strlen(buf)<5) strcpy(inst->modempath,"/dev/modem"); else strncpy(inst->modempath,buf,63); memset(buf,0,256); printf("What is the modem speed [57600]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) *p1=0; if (strlen(buf)==0 || atol(buf)==0L) inst->modemspeed=57600; else inst->modemspeed=atol(buf); memset(buf,0,256); printf ("Should we honor call on ring [Y/n]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) *p1=0; if (strlen(buf)==0 || buf[0]== « r || buf[0]=='y') inst->callonring=1; else inst->callonring=0; memset(buf,0,256); printfC'What serial port is the Pulse Accumulator on [/dev/ttySO]? "); fgets(buf,255,stdin); if (p1=strchr(buf,10)) *p1=0; if (strlen(buf)==0) strcpy(inst->spapath,"/dev/ttySO"); else strncpy(inst->spapath,buf,63); // system("/sbin/ifconfig ethO"); // memset(buf,0,256); // printfC'What is the MAC address of the Ethernet card [REQUIRED]? "); // fgets(buf,255,stdin); // if (p1=strchr(buf,10)) // *p1=0; // for (i=0;i<strlen(buf);i++) // if (buf[i]!=':' && isalpha(buf[i]) && islower(buf[i])) // buf[i]=toupper(buf[i]); // strncpy(inst->mac,buf,63); return(O); } CreateDHCPStartupScript(installstruct * inst) { FILE *f1; f1=fopen(7etc/init.d/dhcp","w"); if (!f1) { printfC'Unable to create /etc/init.d/dhcp, exiting\n"); retum(-1); } fprintf(f1,"#! /bin/sh\n\n"); fprintf(f1,"case \"$1\" in\n"); fprintf(f1," start)\n"); fprintf(f1 ," echo V'Starting dhcp...\"\n"); fprintf(f1," /usr/local/pepper/dhcpcd -h %s\n",inst->hostname); fprintf(f1," sleep 45\n"); fprintf(f1," ;;\n"); fprintf(f1,"esac\n\n"); fclose(f1); chmod("/etc/init.d/dhcp",SJXOTH | SJROTH | SJXGRP | SJRGRP SJXUSR | SJRUSR); if (inst->isdhcp) symlink("/etc/init.d/dhcp","/etc/rc2.d/S91dhcρ"); return(O); } CreatePepperStartupScript(installstruct *inst) { FILE *f1; f1=fopen(7etc/init.d/pepper","w"); if (!f1) { printfC'Unable to create /etc/init.d/pepper, exiting\n"); retum(-1); } fprintf(f1,"#! /bin/sh\n\n"); fprintf(f1,"case \"$1\" in\n"); fprintf(f1," start)\n"); fprintf(f1 ," echo V'Starting pepper... \"\n"); //fprintf(f 1 ," setserial /dev/ttyS2 irq 4 fprintf(f1 ," export OMNIORB_CONFIG=/etc/omniORB.cfg\n"); fprintf(f1 ," export TZ=CST6CDT\n"); if (inst->isethernet) { fprintf(f1 ," echo > /var/lock/corbanet\n"); } fprintf(f1," /usr/local/pepper/callonring %s %s\n",inst->modempath, (inst->callonring?"":"-o")); fprintf(f1 ," /usr/local/pepper/kw_client > /dev/null &\n"); fprintf(f1 ," /usr/local/pepper/swatchdog /etc/pepper/swatchdog.rules\n\n"); fprintf(f1," ;;\n"); fprintf(f1,"esac\n\n"); fclose(fl); chmod("/etc/init.d/pepper",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); symlink("/etc/init.d/pepper","/etc/rc2.d/S99pepper"); return(O); } CreatePPPFiles(installstruct * inst) { FILE *f1; f 1 =fopen(7etc/ppp/ip-up","w"); if (!f1) { printfC'Unable to create /etc/ppp/ip-up, exiting\n"); return(-1); } fprintf(f1,"#!/bϊn/sh\n\n"); // fprintf(f1," /sbin/route add -host 209.219.108.69 pρp0\n"); fprintf(f1 ," /sbin/route add default ppp0\n"); // fprintf(f1 ," /usr/local/pepper/curl http://209.219.108.68/%s\n",inst->hostname); fprintf(f1 ," echo > /var/lock corbanet\n"); fprintf(f1 ," killall -HUP kw_client \n"); fclose(fl); chmod("/etc/ppp/ip-up",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); f1=fopen(7etc/ppp/ip-down","w"); if (!f1) { printfC'Unable to create /etc/ppp/ip-down, exiting\n"); retum(-1); ill } fprintf(f1 ,"#!/bin/sh\n\n"); fprintf(f1 ,"rm /var/lock/corbanet\n"); fprintf(f1 ,"/sbin/route del default pppO\n"); fprintf(f1 ,"/sbin/route add default ethO \n"); fclose(fl); chmod("/etc/ppp/ip-down",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); f1=fopen("/usr/sbin/ppp-on","w"); if (!f1) { printfC'Unable to create /usr/sbin/ppp-on, exiting\n"); return(-1); } fprintf(f1,"#!/bin/sh\n\n"); fprintf(f1 ,"if [ \"$TELEPHONE\" = \T ]; then\n echo Overriding TELEPHONED TELEPHONE=5560085\nfi\n"); fprintf(f1 ,"if [ \"$NETMASK\" = \"\" ]; then \n echo Overriding NETMASKVi NETMASK=255.255.255.0\nfι\n"); fprintf(f1."if [ \"$ACCOUNT\" = \"\" ]; then \n echo Overriding ACCOUNTλn ACCOUNT=stonewater@mindspring.com\nfi\n"); fprintf(f1 ,"if [ \"$PASSWORD\" = \"\" ]; then \n echo Overriding PASSWORDVn PASSWORD=fp8fgyby\nfι\n"); fprintf(f1 ,"#need to put over-ridable ISP userid/passwd here\n"); fprintf(f1 ,"PPPSTART=\"\"\n"); fprintf(f1 ,"RMTRPROMPT=\"\"\n"); fprintf(f1."export ACCOUNT PASSWORD TELEPHONE RMTRPROMPT PPPSTARTλn"); fprintf(f1 ,"DIALER_SCRIPT=/usr/bin/ppp-on-dialer\n"); fprintf(f1."exec /usr/sbin/pppd -detach %s %Id defaultroute connect $DIALER_SCRIPT\n\n",inst->modempath,inst->modemspeed); fclose(f1); chmod("/usr/sbin/ppp-on",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); f1=fopen("/etc/ppp/options","w"); if (!f1) { printfC'Unable to create /etc/ppp/options, exiting\n"); return(-1 ); } fprintf(f1 ,"crtscts\nasyncmap O\nlock\ndefaultroute\n"); fclose(fl); return(O); } CreateDirectoriesQ { mkdir("/usr/locai ,SJXOTH|SJROTH|SJXGRP|SJRGRP|SJXUSR|SJRUSR); mkdir("/usr/local/pepper/",SJXOTH|SJROTH|SJXGRP|SJRGRP|SJXUSR|SJ RUSR); mkdir("/etc/pepper/",SJXOTH|SJROTH|SJXGRP|SJRGRP|SJXUSR|SJRUS R); mkdir("/etc/ppp/",SJXOTH|SJROTH|SJXGRP|SJRGRP|SJXUSR|SJRUSR); return(O); } CreateUpgradeScript(installstruct *inst) { FILE *f1; f1=fopen("/usr/local/pepper/kwupgrade.sh","w"); if (!f1) { printfC'Unable to create /usr/local/pepper/kwupgrade.sh, exiting\n"); return(-1); } fprintf(f1,"#!/bin/sh\n\n"); fprintf(f1 /'echo V'Attempting to download a new kw_client\"\n"); fprintf(f1 ,"rm -f /tmp/kw_client\n\n"); fprintf(f 1 ,"#switch to the RAM disk (to avoid over-exposing the FLASH disk, and because our FLASH disk is full!)\n"); fprintf(f1 ,"/usr/local/pepper/curl ftp://anon:nullpasswd@buster.gnassoc.com/kw_client.glibc%d -o /tmp/kw_client\n\n",inst->glibc); fprintf(f1 ,"#if buster failed, try cara (use IP addr for this one (DNS failure?))\n"); fprintf(f1 ,"if [ ! -f /tmp/kw_client ]; then\n"); fprintf(f1,"echo Trying cara...\n"); fprintf(f1,"/usr/local/pepper/curl ftp://anon:nullpasswd@216.217.51.130/kw_client.glibc%d -o /tmp/kw_client\n",inst->glibc); fprintf(f1,"fi\n\n"); fρrintf(f 1 ,"if [ -f /tmp/kw_client ]; then\n"); fprintf(f1 ," echo V'Found the kw_client, proceeding...\"\n"); fprintf(f 1 ," chmod 744 /tmp/kw_client\n"); fprintf(f1,"else\n"); fprintf(f1 ," echo V'Unable to locate /tmp/kw_client, re-executing /usr/local/pepper/kw_client with upgrade suppression!\"\n"); fprintf(f 1 ," exec /usr/local/pepper/kw_c!ient -L V'Starting with upgrades suppressedΛ" -U\n"); fprintf(f1," exit\n"); fprintf(f1,"fι\n\n"); fprintf(f1,"#only if the executable acts OK do we copy it\n"); fprintf(f1 ,7tmp/kw_client ~testtube\n"); fprintf(f1 ,"if [ $? -eq 99 ]; then\n"); fprintf(f1 ," echo V'Testtube SucceededW); fprintf(f1 ," cp /tmp/kw_client /usr/Iocal/pepper/kw_client\n"); fprintf(f1," rm /tmp/kw_client\n"); fprintf(f1 ," chmod 744 /usr/locaI/pepper/kw_client\n"); fprintf(f1,"else\n"); fprintf(f1 ," echo V'Testtube failed\";\n"); fprintf(f1," /bin/sleep 5\n"); fprintf(f1 ," exec /usr/local/pepper/kw_client -L V'Error in TESTTUBE upgrade\";\n"); fprintf(f1,"fi\n\n\n"); fprintf(f 1 ,"#now close the PPP connection if there is one\n"); fprintf(f1 ,"if [ -f /var/lock/callonring.pid ]; then\n"); fprintf(f1 ," kill -s SIGHUP 'cat /var/lock/callonring.pid^n"); fprintf(f1,"fi\n\n"); fprintf(f1 ,"#now restart kw_client\n"); fprintf(f1 ,"exec /usr/local/pepper/kw_client -FIRSTλn"); fclose(fl); chmod("/usr/local/pepper/kwupgrade.sh",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); return(O); } CreateETCfiles(instalIstruct * inst) { FILE *f1; char buf[256]; int sock; //auto-detect the MAC address...doesn't work :-( //sock=socket(PF INET, SOCK DGRAM, IPPROTO _IP); //ioctl(sock, SIOCGIFHWADDR, buf); //printf("\n\n%s\n\n",buf); // f 1 =fopen("/etc/pepper/mac","w"); // if (!f1) // { // printfC'Unable to create /etc/pepper/mac, exiting\n * '); // return(-1); // } // fprintf(f1 ,"%s",inst->mac); // fclose(fl); f1=fopen("/etc/pepper/swatchdog.rules","w"); if (!f1) { printfC'Unable to create /etc/pepper/swatchdog. rules, exiting\n"); return(-1); } fprintf(f1 ,"#we expect a SIGPROF every 5 minutes (actually happens, every 30 seconds)\n"); fprintf(f1 ,"#regardless of ICCM communication. If we do not get our SIGPROF, it\n"); fprintf(f1 ,"#probably means that our kw_client died completely\n"); fprintf(f1 ,"SIGNAL:27:5\n\n"); fprintf(f1,"FILE:/tmp/commotry\n\n"); fprintf(f1 ,"FILE:/tmp/commosuccess\n"); fclose(fl); //f1=fopen("/etc/pepper/newyorkpulseaccumulator","w"); f 1 =fopen("/etc/pepper/spa1 ","w"); if (!f1) { printfC'Unable to create /etc/pepper/spa1, exiting\n"); return(-1); } fprintf(f1 ,"%s",inst->spapath); fclose( l); f1=fopen("/etc/omniORB.cfg","w"); if (!f1) { printfC'Unable to create /etc/omniORB.cfg, exiting\n"); return(-1); } fprintf(f1,"ORBInitialHost 209.219.108.69\nORBInitialPort 12345\n"); fclose( l); return(O); } FetchEXEs(installstruct * inst) { char buf[1024]; sprintf(buf,"Jcurl ftp://anon:nullpasswd@209.219.108.67/kw_client.glibc%d -o /usr/local/pepper/kw_client\n",inst->glibc); system(buf); chmod(7usr/local/pepper/kw_client",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); sprintf(buf,"Jcurl ftp://anon:nullpasswd@209.219.108.67/callonring.glibc%d -o /usr/local/pepper/callonring\n",inst->glibc); system(buf); chmod(7usr/local/pepper/callonring",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); sprintf(buf,"Jcurl ftp://anon:nullpasswd@209.219.108.67/swatchdog.glibc%d -o /usr/local/pepper/swatchdog\n",inst->glibc); system(buf); chmod("/usr/local/pepper/swatchdog",SJXOTH | SJROTH | SJXGRP | SJRGRP | SJXUSR | SJRUSR); sprintf(buf,"./curl ftp://anon:nullpasswd@209.219.108.67/dhcpcd.glibc%d -o /usr/local/pepper/dhcpcd\n",inst->glibc); system(buf); chmod("/usr/local/pepper/dhcpcd",SJXOTH | SJROTH | SJXGRP | SJRGRP I SJXUSR I SJRUSR); if (FileExists("./curl")) Iink("./curt",7usr/local/pepper/curl"); //create a hard link return(O); } FileExists(const char *filename) { FILE *f1 ; f1 =fopen(filename,"r"); if (!f1) return(O); fclose(f1); return(1); //this return-logic might seem backwards, but we are answering a question } CheckRequiredEXEsQ { int failed; char buf[256]; failed=0; if (!FileExists("curl")) { printf("You must put the program: curl in the local directory for installation to finishΛn"); failed++; } if (!FileExists("dhcpcd")) { printf("WARNING: if this is a dhcp installation, you must put the program: dhcpcd in the local directory An"); printff Do you want to stop installation now [Y/n]? "); fgets(buf,255,stdin); if (strpbrk(buf,"NnfFO")) { return(O); } } return(failed); } main(int argc, char **argv) { installstruct inst; int i; int dhcponly; dhcponly=0; //handle command-line arguments if (argc>1) for (i=1;i<argc;i++) { if (strncasecmp(argv[i],"-v",2)-=0) { printf("Pepper Installer Version 2.8\n"); return(O); } if (strcmp(argv[i],"~dhcp")==0) { dhcponly=1; if (argc-i>1 && argv[i+1][0]!='-') strcpy(inst.hostname, argv[i+1]); else strcpy(inst.hostname,"newlCCM"); } if (strcmp(argv[i],"-testtube")==0) return(99); } if (CheckRequiredEXEsQ) return(-1); CreateDirectoriesQ; if (dhcponly) { CreateDHCPStartupScript(&inst); link("Jdhcpcd","/usr/locaI/pepper/dhcpcd"); //create a hard link printf("DHCP has been installed, exitingΛn"); return(O); } AskAway(&inst); CreateDHCPStartupScript(&inst); CreatePepperStartupScript(&inst); CreatePPPFiles(&inst); CreateUpgradeScript(&inst); CreateETCfiles(&inst); //FetchEXEs(&inst); } FILE: kwjnserterjmpl.h This file is created by the omniORB idl2cpp compiler ========================================================*/ #ifndef _KWJNSERTERJMPL_H #define _KWJNSERTERJMPL_H #include "kwjnserter.hh" #include "dbifaceobj.h" #define KW_CLIENT_VERSION_CODIFIED 0x00000200 #define KW_CLIENT_VERSION_HUMAN "vθ.0.2.0" class kwjnserterjmpl : public virtual _sk_kwjnserter { public: kwJnserterJmplQ; -kwJnserterJmplQ; virtual CORBA::Long KWFactory(char* & new_kwJnserterJOR); virtual CORBA::Long HWLogin(const char * HWADDR); //initial, or after reboot virtual CORBA::Long Login(CORBA::Long deviceid, const char *secret); virtual CORBA:: Boolean UsableQ; virtual CORBA::Boolean Logout(const char * slOR); virtual char *GetTableKey(CORBA:: Long moduleid, CORBA::Long keyid); virtual CORBA::Long SetTableKey(CORBA::Long moduleid, CORBA::Long keyid, const char *val); virtual CORBA::Long GetZoneBySource(CORBA::Long ancestorid, const char * meter_number); virtual CORBA::Long GetMeterlD(CORBA::Long iccmid, const char * metername); virtual CORBA::Long lnsertKW(CORBA::Long zoneid, const char *wwhen, CORBA::Float KW, CORBA::Long scenario=0L); virtual CORBA::Long GetlCCMUpdate(CORBA::Long iccmid); virtual char * GetMeterConf(CORBA::Long iccmid); virtual CORBA::Long GetClock_epoch1999Q; virtual CORBA::Long GetGMTQ; virtual CORBA::Long NeedScheduleQ; virtual CORBA::Long FetchScheduIe(CORBA::Long iccmid, const char * dayofweek, const char *heatlevel); virtual CORBA::Long Version(CORBA::Long iccmid, CORBA::Long codified, const char * humanreadable); virtual CORBA: :Long Watermark(CORBA::Long wmid, CORBA. ong zoneid, const char * wwhen, CORBA::Float KW); virtual char *GetWatermarks(CORBA::Long zoneid); virtual CORBA::Long Log(CORBA::Long zoneid, CORBA::Long code, const char *message, CORBA::Long datetime, CORBA::Long priority); int cleanupQ; //shutdown the db connection virtual char *GetlSPs(CORBA::Long zoneid); virtual char *GetORBs(CORBA::Long zoneid); virtual CORBA::Long GetNotificationCount(CORBA::Long zoneid); virtual CORBA::Long GetNotification(CORBA::Long zoneid, CORBA::Long which, CORBA::Long &facility, CORBA::Long &code1, CORBA::Long &code2); private: //non-CORBA exposed unsigned long zoneid; //OL until logged in DBIFACEObj *DBIFace; int isfactory; }; #endif FILE: kw inserter.cxx this file sets the corba server up to run as a daemon " ===========================================================*/ #include <stdio.h> #include <iostream.h> #include <sys/types.h> #include <sys/wait.h> #include "omnithread.h" #include "kwjnserterjmpl.h" #define USENAMES static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr); int MLog(long codes, const char *body) { dateobj now; printf("%s: %s\n",now.Get("simple",NULL,0),body); fflush(NULL); return(O); } //globals now CORBA::ORB_ptr orb; CORBA::BOA_ptr _myboa; main(int argc, char **argv) { // CORBA: :ORB_ptr orb; // CORBA::BOA_ptr _myboa; pid J superparent; #ifdef DETACH fclose(stdiή); fclose(stdout); superparent=fork(); if (superparent>0) exit(0); //first detach fclose(stdin); fclose(stdout); superparent=fork(); while (superparent > 0) { waitpid(superparent,NULL,0); superparent=fork(); } freopen("/var/log/kwJnserter","a",stdout); freopen("/var/log/kwJnserter","r",stdin); freopen("/var/log/kwJnserter","a",stderr); #endif MLog(1, "Starting kwjnserter server vO.0.2.7'); kwjnserter_var myobjRef; kwjnserterjmpl *kwi; orb=CORBA::ORBJnit(argc, argv,"omniORB2"); _myboa=orb->BOAJnit(argc, argv,"omniORB2_BOA"); kwi=new kwJnserterJmplQ; kwi->_objJs_ready(_myboa); #ifdef USENAMES { myobjRef = kwi->Jhis(); if (!bindObjectToName(orb, myobjRef)) { MLog(9,"Unable to bind to name"); return 1; } } #endif _myboa->implJs_ready(); //the BOA's default behavior is to block forever //getchar(); } #define CONTEXTNAMEID "stonergy" #define CONTEXTNAMEKIND "context" #define NAMEID "kwjnserter" #define NAMEKIND "Object" static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr orb,CORBA::Object_ptr obj) { CosNaming::NamingContext_var rootContext; try{ // Obtain a reference to the root context of the Name service: CORBA::Object_var initServ; initServ = orb->resolveJnitial_references("NameService"); // Narrow the object returned by resolveJnitiaI_references() //to a CosNaming::NamingContext object: rootContext = CosNaming::NamingContext::_narrow(initServ); if (CORBA::is_nil(rootContext)) { cerr « "Failed to narrow naming context ' « endl; return 0; } } catch(CORBA::ORB::lnvalidName& ex) { cerr « "Service required is invalid [does not exist] ' « endl; return 0; } try { // Bind a context called "test" to the root context: CosNaming::Name contextName; contextName.length(l); contextName[0].id = (const char*) CONTEXTNAMEID; // string copied contextName[0].kind = (const char*) CONTEXTNAMEKIND; // string copied // Note on kind: The kind field is used to indicate the type // of the object. This is to avoid conventions such as that used // by files (name.type - e.g. test.ps = postscript etc.) CosNaming::NamingContext_vartestContext; try { // Bind the context to root, and assign testContext to it: testContext = rootContext->bind_new_context(contextName); } catch(CosNaming::NamingContext::AlreadyBound& ex) { // If the context already exists, this exception will be raised. // In this case, just resolve the name and assign testContext // to the object returned: CORBA: :Object_var tmpobj; tmpobj = rootContext->resoIve(contextName); testContext = CosNaming::NamingContext::_narrow(tmpobj); if (CORBA::is_nil(testContext)) { cerr « "Failed to narrow naming context." « endl; return 0; } } // Bind the object (obj) to testContext, naming it Echo: CosNaming::Name objectName; objectName.length(1 ); objectName[0].id = (const char*) NAMEID; // string copied objectName[0].kind = (const char*) NAMEKIND; //string copied // Bind obj with NAMEID Echo to the testContext: try { testContext->bind(objectName,obj); } catch(CosNaming::NamingContext::AlreadyBound& ex) { testContext->rebind(objectName,obj); } // Note: Using rebindQ will overwrite any Object previously bound // to /test Echo with obj. // Alternatively, bindQ can be used, which will raise a // CosNaming::NamingContext::AlreadyBound exception if the name // supplied is already bound to an object. // Amendment: When using OrbixNames, it is necessary to first try bind // and then rebind, as rebind on it's own will throw a NotFoundexception if //the Name has not already been bound. [This is incorrect behaviour - // it should just bind]. } catch (CORBA::COMM_FAILURE& ex) { cerr « "Caught system exception COMM_FAILURE, unable to contact the " « "naming service." « endl; return 0; } catch (omniORB::fatalException& ex) { throw; } catch (...) { cerr « "Caught a system exception while using the naming service."« endl; return 0; } return 1; } FILE: kwdiv.cxx this file implements the server side of kwjnserter corba object #include "kwjnserterjmpl.h" #define TRUE 1 #define FALSE 0 kwjnserterjmpl::kwjnserterjmpl() { zoneid=0L; DBIFace=new DBIFACEObj; } CORBA::Long kwjnserterjmpl::HWLogin(const char *HWADDR) { char qrystr[128]; zoneid=DBIFace->FindHWKey(HWADDR); return(zoneid); } CORBA::Long kwJnserterJmpl::Login(CORBA::Long deviceid, const char * secret) { char qrystr[255]; if (deviceid==0L) retum(OL); DBIFace- >GetTableKey(deviceid,MODULE_KWJNSERTER,KEY_ZONESECRET,qrystr, 255); if (!strcmp(qrystr,secret)) zoneid=deviceid; return(zoneid); } CORBA::Boolean kwJnserterJmpl::Usable() { if (izoneid) return(FALSE); if (DBIFace->Usable()) return(TRUE); else return(FALSE); } CORBA::Long kwJnserterJmpl::GetTableKey(CORBA::Long moduleid, CORBA::Long keyid, char * &dest, CORBA::Long &destlen) { char * temp; if (Izoneid) return(OL); temp=new char[2048]; DBIFace->GetTableKey(zoneid, moduleid, keyid,temp,2047); if (itemp) { dest=NULL; return(OL); } dest=new char[strlen(temp)+1]; memset(dest,0,strlen(temp)+1 ); strcpy(temp,dest); &destlen=strlen(temp); return(strlen(temp)); } CORBA::Long kwJnserterJmpI::lnsertKW(CORBA::Long zoneid, const char *wwhen, CORBA::Float KW, CORBA::Long scenario) { dateobj temp; if (Izoneid) return(OL); temp.Set(wwhen,"simpIe"); DBIFace->lnsertKW(zoneid,&temp,KW,scenario); return(1 L); } CORBA::Long kwJnserterJmpl::GetClock_epoch1999Q { return(OL); //not implemented } CORBA::Long kwJnserterJmpl::NeedSchedule() { return(OL); } CORBA::Long kw_inserterJmpl::FetchSchedule(const char *dayofweek, const char * heatlevel, char * &dest) { return(OL); } FILE: logcodes.h ================================*/ //Log codes: #define LOG_GOTFACTORY 1L #define LOGjBUTTONS 2L #define LOG_FIRSTPASS 3L #define LOG_MISC 4L #defιne LOGj EEDUPGRADE 5L #define LOG_COMMANDLINE 6L #define LOGjΞRRMETERRESOLVE 7L #define LOGjΞRRUPGRADE 8L #define LOG_FETCHCONFIG 9L #define LOGjHWLOGIN 10L //Log timecodes (send actual Julians, except OL means NOW): #define LOGTIME NOW 0L //Log severity levels: #define LOGJNFO 1L #define LOGJNFO1 1L #define LOGJNFO2 2L #define LOGJNFO3 3L #define LOGJNFO44L #define LOGJNFO5 5L #define LOGJNFO6 6L #defιne LOGJNFO7 7L #define LOGJNFO8 8L #define LOGJNFO9 9L #define LOGJNFO10 10L #defιne LOG Λ/ARN 16L #define LOG /VARN1 16L #defιne LOG WARN2 17L #define LOG WARN3 18L #define LOG WARN4 19L #define LOGJWARN5 20L #define LOG Λ/ARN6 21 L #define LOG WARN7 22L #define LOG WARN8 23L #define LOG WARN9 24L #define LOG WARN10 25L #define LOGjΞRR 32L #define LOGJΞRR1 32L #define LOGJΞRR2 33L #define LOGJΞRR3 34L #define LOG_ERR4 35L #define LOGJΞRR5 36L #define LOGJΞRR6 37L #define LOGJΞRR7 38L #define LOGjΞRRδ 39L #define LOGJΞRR940L #define LOG_ERR1041L #define LOG_ACK 64L #define LOG_ACK1 64L #define LOG_ACK2 65L #define LOG_ACK3 66L #define LOG_ACK4 67L #define LOG_ACK568L #define LOGjJNK 128L #define LOGDEBUG 129L; FILE: meterobj.h relevant classes for the pulse accumulator and the a structure to store the information ( readingobj ) ==================================================*/ #ifndef _METEROBJ_H #define METEROBJ H #define RANDOM1 10 #define NEWYORKPULSE1 20 #define SPA1 30 #include <stdio.h> #include <string.h> #include <stdlib.h> #include "dateobj.h" #include "collectionbase.h" #include "drivers, h" #define READINGjREADY 1 #define READING_XMITTED 2 #define READING BUSY 4 class readingobj { public: readingobjQ; int pulses; timej stoptime; int status; int watermarkvetted; }; class meterobj { public: meterobj (); int initialize(char *initstring); float getreading(timej start, timej end); //pulses pre-multiplier int pollQ; int SpyO; int markxmitted(unsigned long which); unsigned long readingcount(); float getreading(unsigned long which); timej getreadingtime(unsigned long which); int WatermarksChecked(unsigned long which); int Remove(unsigned long which); int PollSoon(int minutes=3); unsigned long id; char key[256]; float multiplier; int type; int pollschedule; //# minutes between checks dateobj lastpoll.nextpoll; CollectionBase readings; protected: meter_driver_random1 * r1; meter_driver_newyorkpulse1 *nyp1; meter_driver_spa1 *spa1; int deletedfirstreading; }; #endif FILE meterobj.cxx implementation file for the meterdriver #include "meterobj. h" readingobjr.readingobjQ { pulses=0; stoptime=0; watermarkvetted=0; } meterobj::meterobj() { id=0; memset(key,0,256); type=0; deletedfirstreading=0; pollschedule=30; //default to every half-hour multipliers .0; lastpoll.Set(OL); nextpoll.Set(OL); r1=NULL; nyp1=NULL; spa1=NULL; } int meterobj::initialize(char *initstring) { //num:name:type:multiplier:{rest depends on type} char buf[256]; char stype[256]; char *p1, *p2; int failed; memset(buf,0,256); memset(stype,0,256); lastpolI.Set(OL); nextpoll.Set(OL); //printf("meterobj::initiaIize(\"%s\")\n",initstring); //fflush(NULL); if (strlen(initstring) < 5) { printf("meterobj::initialize() inittstring is too short!\n"); return(O); } failed=0; strncpy(buf,initstring,256); while (isspace(buf[strlen(buf)-1 ])) buf[strlen(buf)-1]=0; p1=strtok(buf,":"); id=atol(p1); p1=strtok(NULL,":"); p2=strtok(NULL,":"); strncpy(key,p1 ,p2-p1-1); p1=p2; // p2=strtok(NULL,":"); // stmcpy(stype,p1 ,p2-p1 -1 ); strncpy(stype,p1 ,256); if (strcmp(stype,"random1")==0) type=RANDOM1; if (strcmp(stype,"newyorkpulse1 ")==0) type=NEWYORKPULSE1 ; if (strcmp(stype,"spa1")==0) type=SPA1; p1=strtok(NULL,":"); pollschedule=atoi(p1 ); p1=strtok(NULL,":"); multiplier=atof(p1 ); p1=strtok(NULL,":"); switch (type) { case RANDOMI: r1=new meter_driver_random1 ; r1->initialize(p1); break; case NEWYORKPULSE1: nyp1=new meter_driver_newyorkpulse1 ; nyp1->initialize(p1); break; case SPAI: spal =new meter_driver_spa1 ; spa1->initialize(p1); break; default: failed++; } return(failed); } int meterobj::poll() { dateobj now; int temppulse; readingobj * tempreading; if ((nextpoll.GetQ == OL) || (nextpoll.GetQ > (now.Get() + ((pollschedule+15) * 60)))) { nextpoll.Set(now.GetBoundry(poIlschedule,1)); printf("Next Poll is at: %s\n",nextpoll.Get("simple",NULL,0)); } // if (inow.lsBoundry(pollschedule) || abs(lastpolI.Get() - now.GetQ) < (pollschedule * 60)) // return(O); if (now.Get() >= nextpoll.GetQ) { printf("Polling meter: %d %s (%s)\n",id,key,now.Get("simpIe",NULL,0)); fflush(NULL); nextpoll.Set(now.GetBoundry(pollschedule, 1 )); printf("Next Poll is at: %s\n",nextpoll.Get("simple",NULL,0)); lastpoll.Set(now.GetQ); temppulse=0; switch (type) { case RAN DOM 1: temppulse=r1->poll(); break; case NEWYORKPULSE1: printf("about to poll channel(id) == %ld (%d)\n",id,(int)id); temppulse=nyp1->poll((int)id-1); break; case SPAI: printf("about to poll spa metersVn"); temppulse=spa1->poll((int)id-1); break; } if (temppulse) { tempreading=new readingobj; tempreading->pulses=temppulse; tempreading->stoptime=Iastpoll.Get(); temρreading->status=READING_READY; if (deletedfirstreading) readings.Add(tempreading); else deletedfirstreading=1 ; SpyO; } } return(O); } int meterobj::Remove(unsigned long which) { readingobj *tempreading; tempreading=(readingobj *)readings.ltem(which); if (itempreading) retum(-1); if (tempreading->status != READING_XMITTED) return(-2); //can't delete a reading until after xmit! return(readings.Remove(which)); //CollectionBase already checks for bounds errors } unsigned long meterobj::readingcount() { return(readings.CountQ); } int meterobj::markxmitted(unsigned long which) { readingobj *temp; if (which < 0 || which > readings.Count()-1) return(-1); temp=(readingobj * )readings.ltem(which); if (temp) temp->status=READING_XMITTED; retum(O); } int meterobj ::WatermarksChecked(unsigned long which) { readingobj *temp; if (which < 0 || which > readings.Count()-1) return(1); temp=(readingobj *)readings.ltem(which); if (temp && temp->status==READING_READY && !temp->watermarkvetted) return(1); else return(O); } float meterobj::getreading(unsigned long which) { readingobj *temp; if (which < 0 || which > readings.Count()-1) return(-LO); temp=(readingobj *)readings.ltem(which); if (temp && temp->status==READING_READY) return(temp->pulses * multiplier); else return(-LO); } timej meterobj::getreadingtime(unsigned long which) { readingobj *temp; if (which < 0 || which > readings.Count()-1) return(OL); temp=(readingobj *)readings.ltem(which); if (temp && temp->status!=READlNGj3USY) return(temp->stoptime); else return(OL); } float meterobj::getreading(timeJ start, timej end) { /*switch (type) { case RAN DOM 1: if (r1) return(r1->getreading(start,end)); case NEWYORKPULSE1: if (nyp1) return(nyp1->getreading(start,end)); case SPA1 : if (spa 1) return(spa1->getreading(start,end)); default: return(O); } 7 int i; readingobj *tempreading; for (i=0;i<readings.Count();i++) { tempreading=(readingobj * )readings.ltem(i); if (tempreading && tempreading->status != READINGJ3USY) { if (tempreading->stoptime >= start && tempreading->stoptime <= end) return(tempreading->pulses * multiplier); } } retum(O.O); } int meterobj ::Spy() { int i; dateobj tdate; readingobj *temp; printfC** ****** * * \nNumber: %d\nlD: %s Type: %d Poll: %d Multiplier: %f\n", id,key,type,polIschedule, multiplier); if (readings.CountQ) { for (i=0;i<readings.Count();i++) { temp=(readingobj *)readings.ltem(i); if (temp) { tdate.Set(temp->stoptime); printf("\t%3.3d\t%s\t%d\n",i,tdate.Get("simple",NULL,0),temp->pulses); } } } fflush(NULL); return(O); } int meterobj::PollSoon(int minutes) { dateobj now; if (nextpoll.GetO - now.GetQ < (minutes * 60)) return(1); else return(O); } FILE: newyorkdev1.fi header for the newyork pulse meter driver #ifndef_NEWYORKDEV1_H #defιne NEWYORKDEV1 H #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <signal.h> #include <ctype.h> #include "dateobj.h" #define BAUDRATE B9600 #define _POSIX_SOURCE 1 /* POSIX compliant source 7 #define FALSE 0 #define TRUE 1 class newyorkdevl { public: newyorkdevl (); int Connect(char * port); int Poll(int whichmeter=-1); int Send(char *buf); int GetLine(char *buf, int size, int timeout); int Get(int which); int Close(); protected: intfd; int newvalue; struct termios oldtio.newtio; }; ģendif FILE: newyorkdevl .cxx Implementation for development version of the newyork pulse accumulator #include "newyorkdev h" #define NYDEBUG newyorkdevl "newyorkdevl () { fd=0; newvalue=0; } int newyorkdevl ::Connect(char *port) { fd=-1; while (fd < 0) { fd = open ort, O_RDWR | O_NOCTTΥ | OjNlONBLOCK); if (fd<0) printf("Error opening NewYorkDevice (%s): ",port); sleep(5); } #ifdef NYDEBUG printf("Modem device %s opened!\n",port); #endif tcgetattr(fd,&oldtio); /* save current serial port settings 7 bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings 7 newtio.c_cflag = BAUDRATE | CLOCAL | CS8 | CREAD; newtio.cjflag = IGNPAR | ICRNL; newtio.c_oflag = 0; newtio.c Iflag = ICANON; newtio.c_cc[VINTR] = 0; /* Ctrl-c 7 newtio.c_cc[VQUIT] = 0; /* Ctrl-\ 7 newtio.c_cc[VERASE] = 0; /* del 7 newtio.c_cc[VKILL] = 0; /* @ 7 newtio.c_cc[VEOF] = 4; /* Ctrl-d 7 newtio.c cc[VTIME] = 0; /* inter-character timer unused 7 newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives 7 newtio.c_cc[VSWTC] = 0; /* '\0' 7 newtio.c_cc[VSTART] = 0; /* Ctrl-q 7 newtio.c_cc[VSTOP] = 0; /* Ctrl-s 7 newtio.c_cc[VSUSP] = 0; / * Ctrl-z 7 newtio.c_cc[VEOL] = 0; / * '\0' 7 newtio.c_cc[VREPRINT] = 0; / * Ctrl-r 7 newtio.c_cc[VDISCARD] = 0; /* Ctrl-u 7 newtio.c_cc[VWERASE] = 0; /* Ctrl-w 7 newtio.c_cc[VLNEXT] = 0; /* Ctrl-v 7 newtio.c_cc[VEOL2] = 0; /* '\0' 7 tcflush(fd, TCIFLUSH); tcsetattr(fd .TCSANOW.&newtio) ; return(O); } int newyorkdevl ::Send(char *buf) { #ifdef NYDEBUG printf("Sending: %s\n",buf); #endif write(fd,buf,strlen(buf)); sleep(1); tcdrain(fd); return(O); } int newyorkdevl ::Getϋne(char * buf, int size, int timeout) { char *p1; int i, remaining, done; dateobj start, now; remaining=size-1 ; i=0; done=0; p1=buf; memset(buf,0,size); while (istrchr uf, 10)) { i=read(fd,p1.remaining); if (i>0) { #ifdef NYDEBUG printf("+%s+",buf); fflush(NULL); #endif p1+=i; remaining-=i; } else printfC'J'); fflush(NULL); now.NowQ; if (now.GetQ - start.GetQ > timeout) return(-1); } return(O); } int newyorkdevl ::Poll(int whichmeter) { int i; char buf[256]; char *p1, *p2; tcflush(fd.TCIOFLUSH); Send("\r"); tcflush(fd,TCIOFLUSH); // while (strncmp(buf,"Box",3)!=0) // Getl_ine(buf,256,5); //get a prompt sprintf(buf,"rd %d\r",whichmeter+1 ); Send(buf); GetLine(buf,256,5) GetLine(buf,256,5) GetLine(buf,256,5) GetLine(buf,256,5) #ifdef NYDEBUG printf("My Pulses: %s\n",buf); #endif p2=strtok(buf,"="); p2=strtok(NULL,"="); if (!p2) { printf("Error getting pulses on channel %d.\n",whichmeter); return(O); } newvalue=atoi(p2); // Send("li\r"); // GetLine(buf,256,5); // Send("cmc001\r"); // GetLine(buf,256,5); sprintf(buf,"cl %d\r",whichmeter+1); Send(buf); GetLine(buf,256,5); #ifdef NYDEBUG printf("%s",buf); #endif return(O); } int newyorkdevl ::Get(int which) { if (which < 0 1| which > 7) return(O); return(newvalue); } int newyorkdevl ::Close() { c!ose(fd); return(tcsetattr(fd,TCSANOW,&oldtio)); } /*===========================================-========= FILE: newyorkpulsel. h header file for the implementation version of the newyorkpulse meter ======================================================*/ #ifndef_NEWYORKPULSE1_H #define _NEWYORKPULSE1_H #include "drivers, h" #include "newyorkdevl. h" class meter_driver_newyorkpulse1 { public: meter_driver_newyorkpulse1 (); int isfluidQ; int initialize(char *initstring); int poll(int whichmeter); unsigned int getreading(time start, timej end); //pulses pre-multiplier protected: int lastval; int newval; int channel; }; #endif FILE: newyorkpulsel .cxx implementation file for production newyork pulse reader #include "newyorkpulsel. h" meter_driver__newyorkpulse1 ::meter_driver_newyorkpulse1 () { } int meter_driver_newyorkpulse1 ::isfluid() { return(O); //the newyorkpulsel driver is not fluid (?) } int meter_driver_newyorkpulse1::initialize(char *initstring) { channel=atoi(initstring); return(O); } int meter_driver_newyorkpulse1::poll(int whichmeter) { //need all of the polling code right here!!! newyorkdevl nyd; FILE *f1; char tempdevice[256]; char *p1; if (!(f1=fopen("/etc/pepper/newyorkpulseaccumulator","r"))) sprintf(tempdevice,"/dev/ttySO"); else { fgets(tempdevice,255,f 1 ); p1 =strchr(tempdevice,':'); if (p1) *p1=0; p1=strchr(tempdevice,10); if (p1) *p1=0; p1 =strchr(tempdevice, 13); if (p1) * P 1=0; fclose(fl); } nyd.Connect(tempdevice); nyd.Poll(channel); newval=nyd.Get(channel); nyd.Close(); return(newval); } unsigned int meter_driver_newyorkpulse1::getreading(timeJ start, timej end) { //pulses are pre-multiplier return(newval); } FILE: notif.h Sets up a data structure to handle curtailment notification. As such it is server side resident. #include "collectionbase.h" #include <unistd.h> class notifications; class notificationobj; class notifications { public: notificationsQ; ~notificationsQ; int Lock(int lockcode, int timeout); int UnLock(int unlockcode); int Add(long facility, long codel, long code2); long CountQ; notificationobj *ltem(long which); int MarkDoneøong which); int RemoveAIIQ; CollectionBase notifs; protected: int internallock; }; class notificationobj { public: notificationobjO; ~notificationobj(); long facility, codel , code2; int processed; }; FILE: notif.cxx This file implements curtailment notification data structures and algorithms =======================================================*/ #include "notif.h" notifications::notifications() { internallock=0; } notifications: :~notifications() { if (CountQ) RemoveAHQ; } int notifications: :Lock(int lockcode, int timeout) { int tries; tries=0; while (internallocki=0) { if (tries > timeout) return(-1); sleep(1); tries++; } internallock=lockcode; return(O); } int notifications::UnLock(int unlockcode) { if (internallock==unIockcode) intemallock=0; } int notifications::Add(long facility, long codel, long code2) { notificationobj *temp; temp=new notificationobj; temp->facility=facility; temp->codei =code1 ; temp->code2=code2; notifs.Add(temp); return(O); } long notifications::Count() { return(notifs.CountQ); } notificationobj *notifications::ltem(long which) { notificationobj *temp; temp=(notificationobj *)notifs.ltem(which); return(temp); } int notifιcations::MarkDone(long which) { notificationobj *temp; temp=(notificationobj * )notifs.ltem(which); if (temp) temp->processed=1 ; else return(-1); return(O); } int notifications::RemoveA!IQ { notifs.RemoveAIIQ; } notificationobj ::notificationobj() { facility=0L; codel =0L code2=0L processed=0; } notificationobj::~notificationobjQ { if (Iprocessed) printffWe are destroying a notificationobj that has not been processed! (%ld,%ld,%ld).\n",facility,code1 ,code2); } FILE: notifier.h _* / #ifndef_NOTIFIER_H #define _NOTIFIER_H #include <stdio.h> #include "easyaddress.h" #include "easyneterror.h" #include "easysocket.h" #include <iostream> #include <string> #include <stdlib.h> using namespace std; class notifierobj { public: int SendEmail(const char *inhost, const char *sender, const char Recipient, const char *subject, const char *body); }; #endif FILE: notifier.cxx implementation file for the email sender #include "notifier.h" int notifierobj::SendEmaiI(const char *inhost, const char * sender, const char * recipient, const char * subject, const char *body) { try { string ipOrHost; string recv; char buf[1024]; string buf2; ipOrHost=inhost; EasyAddress host(ipOrHost); cout « "\n\nTrying to connect on port 25..An"; EasySocket sock(host, 25); sprintf(buf,"mail from: %s\r\n",sender); buf2=buf; sock.Write(buf2); sock.Read(recv,25); cout « recv « endl; sprintf(buf,"rcpt to: %s\r\n",recipient); buf2=buf; sock.Write(buf2); sock.Read(recv,25); cout « recv « endl; sock.Write("DATA\r\n"); //close the SMTP message! sock.Read(recv,25); . cout « recv « endl; sprintf(buf,"From: %s\r\n",sender); buf2=buf; sock.Write(buf2); sprintf(buf,"Reply-To: %s\r\n",sender); buf2=buf; sock.Write(buf2); sprintf(buf,"Subject: %s\r\n\r\n",subject); buf2=buf; sock.Write(buf2); buf.sprintf("%s\r\n",body); buf2=body; sock.Write(buf2); sock.Write("\r\n\r\n.\r\n"); //close the SMTP message! sock.Read(recv,25); cout « recv « endl; sock.Write("quit\r\n"); } catch(EasyNetError &e) { cerr « "An exception occurred in " « e.whereQ « endl; cerr « "Description: " « e.what() « endl; cerr « "Error num: " « e.erromumQ « endl; return EXIT_SUCCESS; } return EXIT_SUCCESS; } FILE: rule.h a helper class that stores the rules for swatchdog #include <stdio.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <utime.h> class rule { public: ruleQ; ~rule(); int initialize(int insignal, int inminutes); int initialize(const char *infilename); int incomingsignal(int which); int checkyourfileQ; int isviolationQ; char logmessage[256]; char filename[256]; int isactiverule; int whichsignal; int XMitLog(const char *logmessage); int tripped_once; protected: timej lastupdate; long minutesallowed; }; FILE: rule.h a helper class that stores the rules for swatchdog ===================================================*/ #include <stdio.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <utime.h> class rule { public: rule(); ~rule(); int initialize(int insignal, int inminutes); int initialize(const char *infilename); int incomingsignal(int which); int checkyourfileO; int isviolationQ; char logmessage[256]; char filename[256]; int isactiverule; int whichsignal; int XMitLog(const char *logmessage); int tripped_once; protected: timej lastupdate; long minutesallowed; }; F!LE: spa1.h Header for stonewater pulse accumulator. ========================================= */ #ifndef _SPA1_H #define _SPA1_H #include "drivers.h" #include "spadevl.h" #include ",./spa2.h" extern spa2 *spaboard; class meter_driver_spa1 { public: meter_driver_spa1 Q; int isfluidQ; int initialize(char *initstring); int poll(int whichmeter); unsigned int getreading(timej start, timej end); //pulses pre-multiplier protected: int lastval; int newval; int channel; static time recentpoll; }; #endif FILE: spal .cxx Implementation file for the stonewater pulse accumulator. =====================================================7 #include "spa1.h" timej meter_driver_spa1 ::recentpoll=(time )0L; meter_driver_spa1 : :meter_driver_spa1 Q { } int meter_driver_spa1::isfluid() { return(O); //the spal driver is not fluid (?) } int meter_driver_spa1::initialize(char *initstring) { channel=atoi(initstring); return(O); } int meter_driver_spa1::poll(int whichmeter) { //need all of the polling code right here!!! spadevl *spa; char buf[16]; dateobj now; #ifdef USETHREADS spa=spaboard->spadev; if (!spa) printf("spaboard->spadev is NULL\n"); #else FILE *f 1 ; char tempdevice[256]; char *p1 ; if (!(f 1 =fopen(7etc/pepper/spa1 ","r"))) sprintf(tempdevice,7dev/ttyS0"); else { fgets(tempdevice,255,f1); p1=strchr(tempdevice,':'); if ( P 1) *p1=0; p1 =strchr(tempdevice, 10); if (p1) *p1=0; p1=strchr(tempdevice,13); if (p1) *p1=0; fclose(f1); } spa=new spadevl ; spa->Connect(tempdevice); #endif if ((now.GetQ-recentpoll) > 59) //if not polled recently, flip-flop & clr { spa->Send("c0"); //clear the inactive buffer spa->GetLine(buf , 16,1); spa->Send("b0"); spa->GetLine(buf,16,1); //flip-flop the active and inactive buffers recentpoll=now.Get(); } spa->Poll(channel); newval=spa->Get(channel); printf("$$$$$$$$$$$$$$$$$\nJust got reading: %d\n$$$$$$$$$$$$$$$$$$\n",newval); #ifndef USETHREADS spa->Close(); delete spa; #endif return(newval); } unsigned int meter_driver_spa1::getreading(timej start, timej end) { //pulses are pre-multiplier return(newval); } File: spa2.h This file is the driver for the stonewater pulse accumulator. =====================================================*/ #ifndef_SPA2_H #define_SPA2_H #include "stonergy_defs.h" #include "meterdrivers/spadevl .h" #define ISRELAY 1 #define ISAUDIO 2 #define ISVOLTAGE 4 class spa2 { public: spa2(); ~spa2(); int connectQ; int activate(unsigned long facility, long paraml, long param2, long param3); int initialize(char *initstring); int poll(int whichmeter); unsigned int getreading(int which, timej start, timej end); //pulses pre- multiplier long housekeepQ; int buttons; int chirps; spadevl *spadev; protected: int connected; static timej recentpoll; char * serialport; int portfiledes; }; #endif FILE: spa2.cxx Implementation file for the driver for the stonewater pulse accumulator. =====================================================7 #include "spa2.h" #include <unistd.h> #include <linux/reboot.h> timej spa2::recentpoϋ=(timeJ)0L; spa2::spa2() { buttons=0; chirps=0; } int spa2::connect() { spadev=new spadevl ; char buf[16]; dateobj now; FILE *f1; char tempdevice[256]; char * p1; if (!(f1 =fopen("/etc/pepper/spa1 ","r"))) { printfC'Unable to open file /etc/pepper/spa1 , this session will ignore the spal device.\n"); fflush(NULL); connected=0; } else { fgets(tempdevice,255,f 1 ); p1=strchr(tempdevice,':'); if (p1) fc p1=0; p1=strchr(tempdevice,10); if (p1) *p1=0; p1 =strchr(tempdevice, 13); if (p1) * P 1=0; fclose(fl); spadev->Connect(tempdevice); connected=1; } } spa2::~spa2() { if (spadev) { spadev->Close(); connected=0; delete spadev; spadev=NULL; } } int spa2::initialize(char *initstring) { return(O); } int spa2::activate(unsigned long facility, long paraml, long param2, long param3) { char buf[9]; if (lconnected) return(-1); memset(buf,0,9); printf("Activate(%ld, %ld, %ld)\n",facility,param1 ,param2); if (facility == RELAY_X ) { if (paraml < OL || paraml > 9L) return(-1); sprintf(buf,"X%c",'0 * +param1 ); } if (facility == RELAY_Y ) { if (paraml < OL || paraml > 9L) return(-1); sprintf(buf,"Y%c",'0'+param1 ); } if (facility == RELAY_Z ) { if (paraml < OL || paraml > 9L) return(-1); sprintf(buf,"Z%c",'0 * +param1); } if (facility == AUDIO_1) { if (paraml < 0 || paraml > 7) return(-1); sprintf(buf,"S%c",O'+param1); } if (facility == VOLTAGE_1) { if (paraml < 0 || paraml > 100 ) retum(-1); sprintf(buf,"V%c",param1 ); } if (facility == VOLTAGE_2) { if (paraml < 0 || paraml > 100 ) return(-1); sprintf(buf,"W%c",param 1 ); } spadev->Send(buf); return(O); } int spa2::poll(int whichmeter) { int newval; dateobj now; char buf[16]; if ((connected) return(-1); if ((now.Get()-recentpolI) > 59) //if not polled recently, flip-flop & clr { spadev->Send("c0"); //clear the inactive buffer spadev->GetLine(buf , 16,1); spadev->Send("bO"); spadev->GetLine(buf,16,1); //flip-flop the active and inactive buffers recentpoll=now.Get(); } spadev->Poll(whichmeter); newval=spadev->Get(whichmeter) ; printf("$$$$$$$$$$$$$$$$$\nJust got reading: %d\n$$$$$$$$$$$$$$$$$$\n",newval); return(newval); } unsigned int spa2::getreading(int channel, timej start, timej end) { //pulses are pre-multiplier if (iconnected) return(-1); return(O); //newval); } long spa2::housekeep() { char buf[32]; if (Iconnected) return(-1); //if chirps > 0 do something spadev->Send("A0"); spadev->GetLine(buf,31 ,5); buttons+=atoi(buf+8); chirps+=atoi(buf+20); if (chirps > 2) { syncQ; //first, try the GLIBC21 rebootQ if (reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART)) { //if that failed, try the GLIBC20 and older rebootQ if (reboot(0xfee1dead,672274793,0x1234567)) system("reboot"); } exit(0); } return(OL); } FILE: spadevl .h Implementation file for the development version of stonewater pulse accumulator. =========================================================:=*/ #ifndef __SPADEV1_H #defιne __SPADEV1_H #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <signal.h> #include <ctype.h> #include "dateobj.h" #define BAUDRATE B9600 #defιne _POSIX_SOURCE 1 /* POSIX compliant source 7 #defϊne FALSE 0 #define TRUE 1 class spadevl { public: spadevl (); int Connect(char * port); int Poll(int whichmeter=-1); int Send(char *buf); int GetLine(char *buf, int size, int timeout); int Get(int which); int CloseQ; protected: int fd; int newvalue; int connected; char portname[256]; struct termios oldtiopewtio; }; #endif FILE: spadevl .cxx Implementation file for the stonewater pulse accumulator development version. =========================================================*/ #include "spadevl .h" #define SPADEBUG 1 spadevl ::spadev1 Q { fd=0; newvalue=0; connected=0; } int spadevl ::Connect(char *port) { if (connected) retum(O); if (port) strncpy(portname,port,255); if (Iport && strlen(portname)==0) strcpy(portname,"/dev/ttySO") ; fd=-1; while (fd < 0) { fd = open ortname, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd<0) printf("Error opening SPA (%s): ".portname); connected=0; sleep(5); } connected=1; #ifdef SPADEBUG printf("Modem device %s opened!\n",port); #endif tcgetattr(fd,&oldtio); /* save current serial port settings 7 bzero(&newtio, sizeof(newtio)); / * clear struct for new port settings 7 newtio.c_cflag = BAUDRATE | CLOCAL | CS8 | CREAD; newtio.cjflag = IGNPAR | ICRNL; newtio.c_oflag = 0; newtio.cjflag = ICANON; newtio.c_cc[VINTR] = 0; /* Ctrl-c 7 newtio.c_cc[VQUIT] = 0; /* Ctrl-\ 7 newtio.c_cc[VERASE] = 0; /* de! 7 newtio.c_cc[VKILL] = 0; /* @ 7 newtio.c_cc[VEOF] = 4; /* Ctrl-d 7 newtio.c_cc[VTIME] = 0; /* inter-character timer unused 7 newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives 7 newtio.c_cc[VSWTC] = 0; /* '\0' 7 newtio.c_cc[VSTART] = 0; /* Ctrl-q 7 newtio.c_cc[VSTOP] = 0; /* Ctrl-s newtio.c_cc[VSUSP] = 0; I* Ctrl-z 7 newtio.c_cc[VEOL] = 0; I* * \0' 7 newtio.c_cc[VREPRINT] = 0; I * Ctrl-r 7 newtio.c_cc[VDISCARD3 = 0; /* Ctri-u 7 newtio.c_cc[VWERASE] = 0; /* Ctrl-w 7 newtio.c_cc[VLNEXT] = 0; /* Ctrl-v 7 newtio.c_cc[VEOL2] = 0; /* * \0' 7 tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); return(O); } int spadevl ::Send(char * buf) { if (iconnected) Connect(NULL); if ('connected) return(-1); #ifdef SPADEBUG printf("Sending: %s\n",buf); #endif write(fd,buf,strlen(buf)); sleep(1); tcdrain(fd); retum(O); } int spadevl ::GetLine(char * buf, int size, int timeout) { char *p1; int i, remaining, done; dateobj start, now; if (iconnected) Connect(NULL); if (iconnected) return(-1); remaining=size-1 ; i=0; done=0; p1=buf; memset(buf.O,size); while (istrchr uf, 10)) { i=read(fd,p1.remaining); if (i>0) { #ifdef SPADEBUG printf("+%s+",buf); fflush(NULL); #endif p1+=i; remaining-=i; } //else // printfC'J'); fflush(NULL); now.NowQ; if (now.GetQ - start.Get() > timeout) return(-1); } return(O); } int spadevl ::Poll(int whichmeter) { int i; char buf[256]; char *p1, * p2; if (iconnected) Connect(NULL); if (iconnected) return(-1); tcflush(fd,TCIOFLUSH); while (GetLine(buf,256,1) != -1); //clear any previous lines sprintf(buf,"r%d",whichmeter); Send(buf); GetLine(buf,256,5); #ifdef SPADEBUG printfC'My Pulses: %s\n",buf); #endif p2=strtok(buf,":"); p2=strtok(NULL,":"); if ('p2) { printf("Error getting pulses on channel %d.\n",whichmeter); return(O); } newvalue=atoi(p2); return(O); } int spadevl ::Get(int which) { if (which < 0 || which > 7) return(O); return(newvalue); } int spadevl ::Close() { close(fd); connected=0; return(tcsetattr(fd,TCSANOW,&oidtio)); } FILE: stdincludes.h A package of header files and releveant classes for the iccm implementation. #ifndef _ STDINCLUDES H #define _ _STDINCLUDES _H #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> class BillEstObj; class BillMeterObj; class ClientlnfoObj; class DBIFACEObj; class LineltemObj; class LineltemsObj; class MadObj; class stonergyprotoengine; class ReadingObj; class RRDLLObj; class RRDLLsObj; class RRMeterRelationObj; class RRMetersObj; class TimePeriodObj; class ZoneNodeObj; class ZoneTreeObj; class RR Base; class Riderβ; #endif FILE: storage. h The header file sets up methods and classes to handle iccm instructions, data, and communications status. =================:==================:=====================*/ #ifndef _ICCM_STORAGE_H #define _ICCM_STORAGE_H #include "iccm_client.h" class storageobj; class schedulerobj; class watermarkobj; class watermarksobj; class watermarkviolation; class storageobj { public: storageobjQ; int LoadMeters(char * conf ile=NULL); long ID(int meter); timej TimeStamp(int meter, int readingindex); float Reading(int meter, int readingindex); int MarkXmitted(int meter, int readingindex); char *GetMeterName(int meter); int DeleteAIIO; int Delete(int meter, int readingindex); int MetersQ; int Readings(int meter); int PollQ; int PollSoon(int minutes=3); int SpyO; int ClearMetersQ; int CheckWatermarks(watermarksobj *wms); protected: CollectionBase cb; unsigned long iccm_zoneid; unsigned long iccm_rootid; }; class schedulerobj { public: schedulerobjQ; int Load(char * section); int istime(const char *description=NULL); int fϊnishedQ; int Later(int minutes); dateobj nextcomm; int addminutes; int busy; }; class watermarksobj { public: watermarksobjQ; int Load(const char *fϊlename); int ClearWatermarksQ; int ClearViolationsQ; //clears violations int Check(unsigned long zoneid, timej wwhen, float kw); int ViolationCount(); watermarkviolation * GetFirst(); watermarkviolation * GetNext(); protected: CollectionBase watermarks; CollectionBase violations; int currviolation; }; class watermarkobj { public: watermarkobjO; int initialize(char *initstring); int set(unsigned long id, unsigned long zoneid, intwmtype, float wm); int Check(unsigned long zoneid, timej wwhen, float kw); unsigned long id; unsigned long zoneid; int wtype; float wm; }; class watermarkviolation { public: watermarkviolationQ; int set(unsigned long wmid, unsigned long zoneid, timej wwhen, float kw); unsigned long wmid; unsigned long zoneid; dateobj wwhen; float kw; }; class ORBsobj { public: ORBsobj(); -ORBsobjQ; int Load(const char * filename); int Add(const char * host, const char *port); CollectionBase cb; }; class ORB { public: ORBQ; char host[256]; char port[32]; dateobj lastsuccess; int failurecount; }; #endif FILE: storage.cxx Implementation for storage on the iccm. Encapsulates the major functionality of the iccm outside of corba. This is the collection that stores information that the client sends and recieves. 7 #include "iccm_client.h" #include "storage.h" storageobj::storageobj() { } int storageobj::LoadMeters(char *conf_file) { FILE *f1; int i.finished; char buf[255]; char * p1; meterobj *temp; f1=fopen(conf_file,"r"); if (!f1) { Log(NOCONF,"Unable to open configuration file"); return(1); } finished=0; while (ifinished && !feof(f1)) { memset(buf,0,255); fgets(buf,254,f1); p1=buf; while(*p1 && isspace(*p1)) p1++; if (p1 && *p1 !='#' && strlen(p1)>5) { temp=new meterobj; temp->initialize(p1); cb.Add(temp); //,atol(p1)); } // else // printf("Skipping empty or comment line in /etc/pepper/meters\n"); } fclose(fl); for(i=0;i<cb.Count();i++) { temp=(meterobj * )cb.ltem(i); if (temp) temp->Spy(); } return(O); } long storageobj::ID(int meter) { meterobj *temp; temp=(meterobj *)cb.ltem(meter); if (Itemp) retum(OL); else return(temp->id); } timej storageobj::TimeStamp(int meter, int readingindex) { meterobj *temp; temp=(meterobj *)cb.ltem(meter); if (temp) return(temp->getreadingtime(readingindex)); else return(OL); } float storageobj: :Reading(int meter, int readingindex) { meterobj *temp; temp=(meterobj *)cb.ltem(meter); if (temp) return(temp->getreading(readingindex)); else return(-LO); } int storageobj::MarkXmitted(int meter, int readingindex) { meterobj * temp; temp=(meterobj * )cb.ltem(meter); if (temp) return(temp->markxmitted(readingindex)); else return(-1); } char * storageobj::GetMeterName(int meter) { meterobj *temp; temp=(meterobj *)cb.ltem(meter); if (temp) return(temp->key); else return(NULL); } int storageobj::DeleteAll() { meterobj *temp; int i,j; for(i=0;i<cb.Count();i++) { temp=(meterobj *)cb.ltem(i); if (temp) { if (temp->readings.CountQ) for(j=0;j<temp->readings.Count();j++) temp->Remove(j); } else printf("storageobj::Delete() Trying to remove non-existant readingW); } return(O); } int storageobj ::Delete(int meter, int readingindex) { meterobj *temp; temp=(meterobj *)cb.ltem(meter); if (temp) temp->Remove(readingindex); else printf("storageobj::Delete() Trying to remove non-existant readingW); return(O); } int storageobj::Meters() { return(cb.CountQ); } int storageobj::Readings(int meter) { meterobj *temp; temp=(meterobj * )cb.ltem(meter); if (temp) return(temp->readingcountQ); else return(O); } int storageobj::PolIQ { int i; meterobj *temp; //Log(0,"Polling all meters"); for (i=0;i<cb.Count();i++) { temp=(meterobj *)cb.ltem(i); if (temp) { temp->poll(); } //printf("Reading on meter %d: %d\n",i,temp->getreading(0,0)); //printfC'Polling meter %d: %d\n" 1 i,temp->poll()); } return(O); } int storageobj::PollSoon(int minutes) { int i; meterobj * temp; for (i=0;i<cb.Count();i++) { temp=(meterobj * )cb.ltem(i); if (temp) if (temp->PollSoon(minutes)) return(1); } return(O); } int storageobj::ClearMeters() { meterobj *temp; int i,j; printf("destroying storageobj\n"); fflush(NULL); for (i=cb.Count()-1;i>=0;i~) { temp=(meterobj *)cb.ltem(i); if (temp) { for (j=temp->readingcount()-1 ;j>=0;j-) temp->Remove(j); cb.Remove(i); } } printfC'storageobj destroyed\n"); fflush(NULL); return(O); } int storageobj::CheckWatermarks(watermarksobj *wms) { meterobj *temp; int i,j; for (i=cb.Count()-1;i>=0;i-) { temp=(meterobj * )cb.ltem(i); if (temp) { for (j=temp->readingcount()-1 ;j>=0;j~) if (!temp->WatermarksChecked(j)) wms->Check(temp->id,temp->getreadingtimeG),temp->getreading(j)); } } return(O); } schedulerobj::schedulerobj() { nextcomm.Set(OL); addminutes=5; busy=0; } int schedulerobj::Load(char *section) { //nextcomm.Set(OL); //addminutes=60; //bad idea (made the first pause after boot-up always 1hr) busy=0; return(O); } int schedulerobj::istime(const char *description) { dateobj now; if (nextcomm.GetQ == OL) nextcomm.Set(now.GetQ); //will commo on startup if (ibusy && nextcomm.GetQ <= now.GetQ) { return(1); } if (description) printf("Next scheduled %s time is: %s %s\n",description,nextcomm.Get("simple",NULL,0),busy?"BUSY":""); fflush(NULL); return(O); } int schedulerobj::Later(int minutes) { nextcom m . N o w() ; nextcomm.Add(minutes * 60); printf("The next Communication schedule is for %s (added %d minutes).\n",nextcomm.Get("simple",NULL,0), minutes); return(O); } int schedulerobj::finished() { Later(addminutes); //add specified minutes until next commo printf("lnside ::fιnished() Next commoschedule is for: %s\n",nextcomm.Get("simple",NULL,0)); busy=0; return(O); } watermarksobj: :watermarksobj() { currviolation=0; } int watermarksobj: :Load(const char *filename) { FILE *f1; int finished, i; char buf[256]; char *p1; watermarkobj *temp; ClearWatermarksQ; ClearViolationsO; f 1 =fopen(fiiename,"r"); if (Ifi) { Log(NOCONF,"Unable to open watermarks file for reading."); return(1); } finished=0; while (ifinished && !feof(f1)) { memset(buf,0,256); fgets(buf,255,f1); p1=buf; while(*p1 && isspace(*p1)) p1++; if (p1 && *p1 !='#' && strlen(p1)>5) { temp=new watermarkobj; temp->initialize(p1); watermarks.Add(temp); } // else // printf("Skipping empty or comment line in /etc/pepperpepper//watermarks\n"); } fclose(f1); for (i=0;i<watermarks,Count();i++) { temp=(waterrnarkobj *)watermarks.Item(i); printfC'Watermark Spy: %ld %Id %d %f\n",temp->id,temp->zoneid,temp- >wtype,temp->wm); } return(O); } int watermarksobj::ClearWatermarksQ { watermarkobj *temp; int i; for (i=watermarks.Count()-1 ;i>=0;i-) { // temp=(watermarkobj *)watermarks.ltem(i); // if (temp) // delete temp; watermarks.Remove(i); } return(O); } int watermarksobj::ClearViolationsQ //clears violations { watermarkviolation * temp; int i; currviolation=0; for (i=violations.Count()-1 ;i>=0;i— ) { // temp=(watermarkviolation *)violations.ltem(i); // if (temp) // delete temp; violations . Remove(i) ; } return(O); } int watermarksobj::Check(unsigned long zoneid, timej wwhen, float kw) { watermarkobj *temp; watermarkviolation *temp2; int i.retval; retval=0; //printfC'Checking Watermark: zone=%ld\tkw=%f\n",zoneid,kw); for (i=0;i<watermarks.Count();i++) { //printf(">"); temp=(watermarkobj *)watermarks.ltem(i); if (temp) { if (temp->Check(zoneid,wwhen,kw)) { printfC'Watermark %ld violated (%f KW).\n",temp->id,kw); temp2=new watermarkviolation; temp2->set(temp->id,zoneid,wwhen,kw); violations.Add(temp2); retval++; } } else printf("Error getting pointer to watermarkobjΛn"); } return(retval); } intwatermarksobj::ViolationCount() { return(violations.CountQ); } watermarkviolation * watermarksobj::GetFirst() { currviolation=-1; return(GetNextQ); } watermarkviolation *watermarksobj::GetNext() { watermarkviolation * temp; currviolation++; if (currviolation >= violations.CountQ) return(NULL); temp=(watermarkviolation *)violations.ltem(currviolation); return(temp); } watermarkobj::watermarkobj() { id=0L; zoneid=0L; wtype=0; wm=0.0; } int watermarkobj::initialize(char *initstring) { //id :zoneid : wtype: val ue char buf[256]; char swtype[256]; char *p1,*p2; memset(buf,0,256); if (strlen(initstring) < 5) { printf("watermarkobj::initialize() inittstring is too short!\n"); return(O); } strncpy(buf,initstring,256); while (isspace(buf[strlen(buf)-1])) buf[strlen(buf)-1]=0; ρ1=strtok(buf ,":"); id=atol(p1); p1=strtok(NULL,":"); zoneid=atol(p1); memset(swtype,0,256); p1=strtok(NULL,":"); p2=strtok(NULL,":"); stmcpy(swtype,p1 ,p2-p1-1); p1=p2; //printf("GARBAGE: |%s|\n" 1 swtype); fflush(stdout); if (strcasecmp(swtype,"HI")==0) wtype=HIWATER; if (strcasecmp(swtype,"LO")==0) wtype=LOWATER; if (strcasecmp(swtype,"EQ")==0) wtype=EQWATER; if (strcasecmp(swtype,"LONZ")==0) wtype=LOWATERNZ; //p1=strtok(NULL,":"); wm=atof(p1); retum(O); } int watermarkobj::set(unsigned long iid, unsigned long izoneid, int iwtype, float iwm) { id=iid; zoneid=izoneid; wtype=iwtype; wm=iwm; } int watermarkobj::Check(unsigned long izoneid, timej wwhen, float kw) { //printfC'\t%ld\t%f\t\t%ld\t%d\t%An",izoneid,kw,zoneid,wtype,wm); if (izoneid==zoneid) { switch (wtype) { case HIWATER: if (kw>wm) return(1); break; case LOWATER: if (kw<wm) return(1); break; case EQWATER: if (kw==wm) return(1); break; case LOWATERNZ: if (kw != 0.0 && kw < wm) return(1); break; } } return(O); } watermarkviolation::watermarkviolation() { set(0L,0L,0,O.0); } int watermarkviolation::set(unsigned long iwmid, unsigned long izoneid, timej iwwhen, float ikw) { wmid=iwmid; zoneid=izoneid; wwhen.Set(iwwhen); kw=ikw; return(O); } ORBsobj::ORBsobj() { } ORBsobj::~ORBsobjQ { cb.RemoveAIIQ; } int ORBsobj::Load(const char *filename) { FILE *f1 ; char buf[1024]; char * p1; f1 =fopen(filename,"r"); if (f1==NULL) { printfC'Unable to open new orbs!\n"); if (cb.CountQ < 5) { Add("209.219.108.69","12345"); Add("209.219.108.70","12345"); Add("corba.stonewatersoft are.com","12345"); Add("corba2.stonewatersoftware.com","12345"); Add("buster.stonewatersoftware.com","12345"); } retum(-1); } cb.RemoveAIIQ; while(Jfeof(f1)) { memset(buf,0,1024); fgets(buf,1023,f1); if (strlen(buf)) { while (isspace(buf[strlen(buf)-1 ])) buf[strlen(buf)-1]=0; p1=strchr(buf,':'); <f (!p1) continue; //not a valid entry *p1=0; p1++; Add(buf.pl); } } fclose(f1); } int ORBsobj::Add(const char *host, const char * port) { ORB *temp; temp=new ORB; strncpy(temp->host, host, 255); strncpy(temp->port, port, 31); cb.Add(temp); retum(O); } ORB::ORB() { memset(host,0,256); memset(port,0,32); lastsuccess.Set(OL); failurecount=0; } FILE: swatchdog. cxx swatchdog watches the iccm clinet to see when it needs to be rebooted. #iήclude <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <time.h> #include <signal.h> #include <stdlib.h> #include <ctype.h> #include <sys/wait.h> #include "rule.h" //prototypes int LoadRules(const char *filename, rule * rules); int ShowHelpQ; int InstallSignalHandler(int which); int GotSignal(int which); int TrapSignals(rule *rules); int CheckViolations(rule *rules); int lnvokeAIIRules(rule *rules); int DoRebootQ; int DetachQ; int writepidfile(const char * filename); void sighandler(int which) { GotSignal(which); } //global rule rules[64]; main(int argc, char **argv) { if (argc<2) { ShowHelpQ; return(1); } DetachO; LoadRules(argv[1], rules); TrapSignals(rules); while (1) { InvokeAIIRules(rules); if (CheckViolations(rules)) DoReboot(); sleep(30); } exit(0); } int writepidfιle(const char * filename) { FILE *f1; f 1 =fopen(filename,"w"); if (!f1) return(-1); fprintf(f1 ,"%d\n",getpidQ); fclose(fl); return(O); } DetachQ . { pid J a,b,c; fclose(stdin); fclose(stdout); a=fork(); if (a > 0) { //waitpid(superparent,NULL,0); exit(0); } // b=fork(); // if (b>0) // { waitpid(b,NULL,0); fprintf(stderr,"Swatchdog child was killed...rebootingΛn"); DoRebootQ; } else writepidfile("/var/lock/swatchdog.pid"); freopen(7var/log/swatchdog","a",stdout); freopen("/var/log/swatchdog","r",stdin); freopen("/var/log/swatchdog","a",stderr); return(O); } DoRebootQ { printfC**************** ReBooting in 3 minutes * ** ********** * ** *\n"); sleeρ(360); printf("******************** ReBooting NOW!!! ********** ** *******\ n "); system("/sbin/reboot"); exit(99); } lnvokeAIIRules(ruIe *rules) { int i; for (i=0;i<64;i++) { if (rules[i].whichsignal == 0) rules[i].checkyourfile(); } retum(O); } GotSignal(int which) { int i; for (i=0;i<64;i++) { if (rules[i].whichsignal ==which) rules[i].incomingsignal(which); } return(O); } CheckViolations(rule *rules) { int i; for (i=0;i<64;i++) { if (rules[i].isvio!ation()) return(1); } retum(O); } TrapSignals(rule *rules) { int i; for (i=0;i<64;i++) { if (rules[i].whichsigna! > 0) lnstallSignalHandler(ru!es[i].whichsignal); } return(O); } LoadRules(const char * filename, rule *rules) { FILE *f1; char buf[256]; int signum, numminutes, currrule; char *p1, *p2; f1=fopen(filename,"r"); if (!f1) { printfC'Unable to open the swatchdog rules fileΛn"); return(-1); } currrule=0; while (!feof(f1)) { memset(buf,0,256); fgets(buf,255,f1); if (strlen(buf)<5) continue; if (strncasecmp(buf,"SIGNAL",6)==0) { p1=strtok(buf,":"); p1=strtok(NULL,":"); signum=atoi(p1); p1=strtok(NULL,":"); numminutes=atoi(p1); rules[currrule].initialize(signum, numminutes); currrule++; } if (strncasecmp(buf,"FILE" ) 4)==0) { ρ1=strtok(buf,":"); p1=strtok(NULL,":"); p2=p1; while (!isspace(*p2)) p2++; *p2=0; rules[currrule].initialize(p1); currrule++; } } fclose(f1); return(O); } int InstallSignalHandIer(int which) { struct sigaction sa; sa.sa_handler=sighandler; sa.sa_flags=SA_RESTART; sigaction(which,&sa,NULL); return(O); } int ShowHelpQ { printfC'Swatchdog v2.7, Copyright 2000, Stonewater Software, lnc.\n\n"); printf("Usage:\n\tswatchdog [-1 outlogfile] [-kh sighup_frequency] [-ku siguser2Jrequency] [-vp processname] filename [filename ...]\n\n\n"); printf("\t-l outfile\t\tthe path and name of the file into which severe \n\t\t\t\tlog entries should be put\n\n"); " printf("\t-kh sighup Jrequency\tif swatchdog does not receive a sighup \n\t\t\t\tevery sighup Jrequency minutes, then it\n\t\t\t\twill reboot\n\n"); printf("\t-ku siguser2Jrequency\tif swatchdog does not receive a \n\t\t\t\tsiguser2 signal every siguser2Jrequency\n\t\t\t\tminutes, then it will reboot\n\n"); printf("Vt-vp processname\t\tjust before reboot, swatchdog will check to \n\t\t\t\tsee if the specified process is running and log \n\t\t\t\tthe presence/absence of the specified \n\t\t\t\tprocess name, -vp can be invoked multiple \n\t\t\t\ttimes to watch up to 5 process names\n\n"); printf("\tfilename\t\tthis should be the complete path to a text \n\t\t\t\tfile. This text file should contain a number, \n\t\t\t\twhich is the maximum number of minutes old\n\t\t\t\tthat the file is allowed to be before \n\t\t\t\tswatchdog reboots the system\n\n"); return(O); } IMAGE EVflLUflTION TEST TARGET Qfl-3 1.0 lϋέ f 2.2 I.! L8 11.25 1.4 Lό

Claims: WHAT IS CLAIMED IS: 1. A system for monitoring and controlling energy distribution from at least one Energy Service Provider, comprising: a publicly accessible distributed network; a network access device that interfaces power monitoring and power curtailment circuitry to said distributed network; and a management device that supports interfaces to said power monitoring and said power curtailment circuitry, said management device located remotely from said network access device, and comprising a control device that interfaces said network access device through said publicly accessible distributed network, wherein said management device controls electrical loads at a remote location based in part on market prices of electricity. 2. The system of claim 1 wherein said network access device is located at said remote location and said control device interfaces said network access device automatically at a predetermined time interval. 3. The system of claim 1 wherein said management device controls electrical power distribution to said remote location based on the available supply of electric power from said at least one Electric Service Provider. 4. The system of claim 1 wherein said network access device further comprises a Carrier Sense Multiple Access with Collision Detection interface that regulates communication between said network access device and an external device at said remote location. 5. The system of claim 1 further comprising a communication device interfaced with said management device that automatically notifies a user of an anticipated load reduction. 6. The system of claim 1 further comprising an interface that supports communication from an input and an output device interconnected with said publicly accessible distributed network and located remotely from said network access device. 7. The system of claim 6 wherein said input and said output device is located remotely from said management device. 8. The system of claim 6 wherein said interface comprises at least one of a command-line interface, a menu-driven interface, and a graphical user interface. 9. The system of claim 6 wherein said input device comprises a keyboard and said output device comprises a terminal. 10. The system of claim 1 wherein said network access device further comprises a pulse accumulator interfaced to said power monitoring circuitry. 11. The system of claim 10 wherein said network access device further comprises a multiplier interfaced to said pulse accumulator to measure electrical energy monitored by said power monitoring circuitry. 12. The system of claim 1 wherein said network access device is a programmable device that stores data in a memory. 13. The system of claim 1 wherein said network access device further comprises a programmable FLASH memory that retains at least one of an Operating System Software and a System Software, and wherein said Flash memory is configured to receive said Operating System Software and said System Software on a command of said management device. 14. The system of claim 1 wherein said network access device comprises a plurality of E1-2000s located remotely from said management device. 15. The system of claim 14 wherein each of said Internet Customer Curtailment Modules share a common identification code that allows said Internet Customer Curtailment Modules to interconnect with said publicly accessible distributed network through a single service provider account. 16. The system of claim 1 wherein said publicly accessible distributed network comprises the Internet. 17. The system of claim 1 further comprising at least one of a visual and an audible alarm electrically interconnected with said network access device. 18. The system of claim 1 wherein said management device further comprises a management clock and said network access device further comprises a network clock that is synchronized to said management clock when said management device interfaces said network access device. 19. The system of claiml further comprising a plurality of manually activated switches wherein at least one switch is adapted to initiate a connection between said network access device and said management device and at least one switch is adapted to reset said network access device. 20. The system of claim 1 further comprising at least one manually activated switch adapted to initiate a connection between said network access device and said management device when actuating a first state and adapted to reset said network access device when actuating a second state. 21. A system for monitoring and redistributing energy, comprising: a publicly accessible network; an energy exchange interfaced to said publicly accessible network; an E1-2000 interfaced to power monitoring circuitry, power curtailment circuitry and said publicly accessible network; an on-line Site interfaced to said E1-2000 and said energy exchange through said publicly accessible network, said on-line Site facilitating energy redistribution by monitoring power consumption data through said E1-2000, price data through said energy exchange, and initiating curtailment events through said E1-2000. 22. The system of claim 21 , wherein said E1-2000 comprises software and said on-line Site interface to said E1-2000 is a periodic interface controlled by said software. 23. The system of claim 21 , wherein said E1-2000 comprises a modem and an Ethernet device and said on-line Site interface to said E1-2000 occurs through one of said modem and said Ethernet device. 24. The system of claim 21 , wherein said E1-2000 comprises a wireless device and said on-line Site interface to said E1-2000 occurs through said wireless device. 25. The system of claim 21, wherein said on-line Site comprises a communication server, a database server, and a Web application server. 26. The system of claim 25, wherein each of said communication, database, and Web application servers further comprise secondary servers that backup each of said communication, database, and Web application servers. 27. The system of claim 21 , wherein said publicly accessible network is the Internet. 28. The system of claim 21 , wherein said E1-2000 is a programmable device can be programmed through said on-line Site. 29. The system of claim 21 , wherein said E1-2000 is responsive to a ring instruction. 30. The system of claim 21 further comprising an end-user interface, an energy supplier interface, and an administrative interface wherein each of said interfaces are located remotely from one another. 31. The system of claim 21 wherein said on-line Site interface to said E1- 2000 is a continuous interface that allows said on-line Site to monitor price data and power consumption data in real-time. 32. A method of monitoring and controlling energy distribution, comprising: monitoring electrical load data from a plurality of distributed locations and electric market supply data through a publicly accessible distributed network; and receiving said data at an on-line Site connected to said publicly accessible distributed network, said on-line Site processing said electrical load and said market supply data and initiating at least one power curtailment request at one of said distributed locations based on said electrical load data and said market supply data. 33. The method of claim 32 further comprising sending at least one message selected from the group comprising an electronic mail message, a pager message, and a facsimile message. 34. The method of claim 32, further comprising initiating at least one of a visual and an audible alarm before initiating said at least one power curtailment request. 35. The method of claim 32, wherein said power curtailmentrequest comprises at least one wireless message. 36. The method of claim 32, further comprising providing user's with user definable reports. 37. The method of claim 32, further comprising interfacing a network access device to said publicly accessible distributed network automatically at programmable timed intervals. 38. The method of claim 37, further comprising a control device initiating a momentary interface to said network access device which causes said network access device to interface a management device. 39. The method of claim 32, wherein said market supply data comprises market prices of electric power. 40. The method of claim 32, wherein said at least one power curtailment requests comprises a power curtailment event.

Inventors: HEFFERNAN JAMES RONAN, NIERLICH GERD W, HEFFERNAN, JAMES, RONAN, NIERLICH, GERD, W.
Applicants: STONEWATER SOFTWARE INC, STONEWATER SOFTWARE, INC.
Application year: 2001
Main classification: G05D11
IPC codes: G06Q50, H02J3, H02J13